Commit 83fbeb9f authored by Patryk Wlazlyn's avatar Patryk Wlazlyn Committed by Len Brown
Browse files

tools/power turbostat: Allow adding PMT counters directly by sysfs path



Allow user to add PMT counters by either identifying the source with:
  guid=%u,seq=%u
or, since this patch, with direct sysfs path:
  path=%s, for example path=/sys/class/intel_pmt/telem5

In the later case, the guid and sequence number will be infered
by turbostat.

Signed-off-by: default avatarPatryk Wlazlyn <patryk.wlazlyn@linux.intel.com>
Signed-off-by: default avatarLen Brown <len.brown@intel.com>
parent 16ce4678
Loading
Loading
Loading
Loading
+106 −1
Original line number Diff line number Diff line
@@ -9788,11 +9788,96 @@ bool starts_with(const char *str, const char *prefix)
	return strncmp(prefix, str, strlen(prefix)) == 0;
}

int pmt_parse_from_path(const char *target_path, unsigned int *out_guid, unsigned int *out_seq)
{
	struct pmt_diriter_t pmt_iter;
	const struct dirent *dirname;
	struct stat stat, target_stat;
	int fd_telem_dir = -1;
	int fd_target_dir;
	unsigned int seq = 0;
	unsigned long guid, target_guid;
	int ret = -1;

	fd_target_dir = open(target_path, O_RDONLY | O_DIRECTORY);
	if (fd_target_dir == -1) {
		return -1;
	}

	if (fstat(fd_target_dir, &target_stat) == -1) {
		fprintf(stderr, "%s: Failed to stat the target: %s", __func__, strerror(errno));
		exit(1);
	}

	if (parse_telem_info_file(fd_target_dir, "guid", "%lx", &target_guid)) {
		fprintf(stderr, "%s: Failed to parse the target guid file: %s", __func__, strerror(errno));
		exit(1);
	}

	close(fd_target_dir);

	pmt_diriter_init(&pmt_iter);

	for (dirname = pmt_diriter_begin(&pmt_iter, SYSFS_TELEM_PATH); dirname != NULL;
	     dirname = pmt_diriter_next(&pmt_iter)) {

		fd_telem_dir = openat(dirfd(pmt_iter.dir), dirname->d_name, O_RDONLY | O_DIRECTORY);
		if (fd_telem_dir == -1) {
			continue;
		}

		if (parse_telem_info_file(fd_telem_dir, "guid", "%lx", &guid)) {
			fprintf(stderr, "%s: Failed to parse the guid file: %s", __func__, strerror(errno));
			continue;
		}

		if (fstat(fd_telem_dir, &stat) == -1) {
			fprintf(stderr, "%s: Failed to stat %s directory: %s", __func__,
				dirname->d_name, strerror(errno));
			continue;
		}

		/*
		 * If reached the same directory as target, exit the loop.
		 * Seq has the correct value now.
		 */
		if (stat.st_dev == target_stat.st_dev && stat.st_ino == target_stat.st_ino) {
			ret = 0;
			break;
		}

		/*
		 * If reached directory with the same guid,
		 * but it's not the target directory yet,
		 * increment seq and continue the search.
		 */
		if (guid == target_guid)
			++seq;

		close(fd_telem_dir);
		fd_telem_dir = -1;
	}

	pmt_diriter_remove(&pmt_iter);

	if (fd_telem_dir != -1)
		close(fd_telem_dir);

	if (!ret) {
		*out_guid = target_guid;
		*out_seq = seq;
	}

	return ret;
}

void parse_add_command_pmt(char *add_command)
{
	char *name = NULL;
	char *type_name = NULL;
	char *format_name = NULL;
	char *direct_path = NULL;
	static const char direct_path_prefix[] = "path=";
	unsigned int offset;
	unsigned int lsb;
	unsigned int msb;
@@ -9881,6 +9966,10 @@ void parse_add_command_pmt(char *add_command)
			goto next;
		}

		if (strncmp(add_command, direct_path_prefix, strlen(direct_path_prefix)) == 0) {
			direct_path = add_command + strlen(direct_path_prefix);
			goto next;
		}
next:
		add_command = strchr(add_command, ',');
		if (add_command) {
@@ -9952,8 +10041,24 @@ void parse_add_command_pmt(char *add_command)
		exit(1);
	}

	if (direct_path && has_guid) {
		printf("%s: path and guid+seq parameters are mutually exclusive\n"
		       "notice: passed guid=0x%x and path=%s\n", __func__, guid, direct_path);
		exit(1);
	}

	if (direct_path) {
		if (pmt_parse_from_path(direct_path, &guid, &seq)) {
			printf("%s: failed to parse PMT file from %s\n", __func__, direct_path);
			exit(1);
		}

		/* GUID was just infered from the direct path. */
		has_guid = true;
	}

	if (!has_guid) {
		printf("%s: missing %s\n", __func__, "guid");
		printf("%s: missing %s\n", __func__, "guid or path");
		exit(1);
	}