tools/power turbostat: Allow mapping multiple PMT files with the same GUID

Some platforms may expose multiple telemetry files identified with the
same GUID. Interpreting it correctly, to associate given counter with a
CPU, core or a package requires more metadata from the user.

Parse and create ordered, linked list of those PMT aggregators, so that
we can identify specific aggregator with GUID + sequence number.

Signed-off-by: Patryk Wlazlyn <patryk.wlazlyn@linux.intel.com>
Signed-off-by: Len Brown <len.brown@intel.com>

authored by Patryk Wlazlyn and committed by Len Brown 16ce4678 4265a865

+40 -35
+40 -35
tools/power/x86/turbostat/turbostat.c
··· 9033 9033 9034 9034 struct pmt_mmio *pmt_mmio_open(unsigned int target_guid) 9035 9035 { 9036 - DIR *dirp; 9037 - struct dirent *entry; 9036 + struct pmt_diriter_t pmt_iter; 9037 + const struct dirent *entry; 9038 9038 struct stat st; 9039 - unsigned int telem_idx; 9040 9039 int fd_telem_dir, fd_pmt; 9041 9040 unsigned long guid, size, offset; 9042 9041 size_t mmap_size; 9043 9042 void *mmio; 9044 - struct pmt_mmio *ret = NULL; 9043 + struct pmt_mmio *head = NULL, *last = NULL; 9044 + struct pmt_mmio *new_pmt = NULL; 9045 9045 9046 9046 if (stat(SYSFS_TELEM_PATH, &st) == -1) 9047 9047 return NULL; 9048 9048 9049 - dirp = opendir(SYSFS_TELEM_PATH); 9050 - if (dirp == NULL) 9049 + pmt_diriter_init(&pmt_iter); 9050 + entry = pmt_diriter_begin(&pmt_iter, SYSFS_TELEM_PATH); 9051 + if (!entry) { 9052 + pmt_diriter_remove(&pmt_iter); 9051 9053 return NULL; 9054 + } 9052 9055 9053 - for (;;) { 9054 - entry = readdir(dirp); 9055 - 9056 - if (entry == NULL) 9057 - break; 9058 - 9059 - if (strcmp(entry->d_name, ".") == 0) 9060 - continue; 9061 - 9062 - if (strcmp(entry->d_name, "..") == 0) 9063 - continue; 9064 - 9065 - if (sscanf(entry->d_name, "telem%u", &telem_idx) != 1) 9066 - continue; 9067 - 9068 - if (fstatat(dirfd(dirp), entry->d_name, &st, 0) == -1) { 9056 + for (;entry != NULL; entry = pmt_diriter_next(&pmt_iter)) { 9057 + if (fstatat(dirfd(pmt_iter.dir), entry->d_name, &st, 0) == -1) { 9069 9058 break; 9070 9059 } 9071 9060 9072 9061 if (!S_ISDIR(st.st_mode)) 9073 9062 continue; 9074 9063 9075 - fd_telem_dir = openat(dirfd(dirp), entry->d_name, O_RDONLY); 9064 + fd_telem_dir = openat(dirfd(pmt_iter.dir), entry->d_name, O_RDONLY); 9076 9065 if (fd_telem_dir == -1) { 9077 9066 break; 9078 9067 } ··· 9095 9106 mmap_size = ROUND_UP_TO_PAGE_SIZE(size); 9096 9107 mmio = mmap(0, mmap_size, PROT_READ, MAP_SHARED, fd_pmt, 0); 9097 9108 if (mmio != MAP_FAILED) { 9098 - 9099 9109 if (debug) 9100 9110 fprintf(stderr, "%s: 0x%lx mmaped at: %p\n", __func__, guid, mmio); 9101 9111 9102 - ret = calloc(1, sizeof(*ret)); 9112 + new_pmt = calloc(1, sizeof(*new_pmt)); 9103 9113 9104 - if (!ret) { 9114 + if (!new_pmt) { 9105 9115 fprintf(stderr, "%s: Failed to allocate pmt_mmio\n", __func__); 9106 9116 exit(1); 9107 9117 } 9108 9118 9109 - ret->guid = guid; 9110 - ret->mmio_base = mmio; 9111 - ret->pmt_offset = offset; 9112 - ret->size = size; 9119 + /* 9120 + * Create linked list of mmaped regions, 9121 + * but preserve the ordering from sysfs. 9122 + * Ordering is important for the user to 9123 + * use the seq=%u parameter when adding a counter. 9124 + */ 9125 + new_pmt->guid = guid; 9126 + new_pmt->mmio_base = mmio; 9127 + new_pmt->pmt_offset = offset; 9128 + new_pmt->size = size; 9129 + new_pmt->next = pmt_mmios; 9113 9130 9114 - ret->next = pmt_mmios; 9115 - pmt_mmios = ret; 9131 + if (last) 9132 + last->next = new_pmt; 9133 + else 9134 + head = new_pmt; 9135 + 9136 + last = new_pmt; 9116 9137 } 9117 9138 9118 9139 loop_cleanup_and_break: 9119 9140 close(fd_pmt); 9120 9141 close(fd_telem_dir); 9121 - break; 9122 9142 } 9123 9143 9124 - closedir(dirp); 9144 + pmt_diriter_remove(&pmt_iter); 9125 9145 9126 - return ret; 9146 + /* 9147 + * If we found something, stick just 9148 + * created linked list to the front. 9149 + */ 9150 + if (head) 9151 + pmt_mmios = head; 9152 + 9153 + return head; 9127 9154 } 9128 9155 9129 9156 struct pmt_mmio *pmt_mmio_find(unsigned int guid)