From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by gabe.freedesktop.org (Postfix) with ESMTPS id 67D0010E07B for ; Wed, 1 Feb 2023 00:01:02 +0000 (UTC) Message-ID: <741862eb-8a8c-a1b6-d033-0f6f09f1c40d@intel.com> Date: Tue, 31 Jan 2023 19:04:23 -0500 From: "Dong, Zhanjun" To: Alan Previn , References: <20221206085849.271505-3-alan.previn.teres.alexis@intel.com> Content-Language: en-US In-Reply-To: <20221206085849.271505-3-alan.previn.teres.alexis@intel.com> Content-Type: text/plain; charset="UTF-8"; format=flowed Content-Transfer-Encoding: 7bit MIME-Version: 1.0 Subject: Re: [igt-dev] [i-g-t, v2, 02/11] tools/intel_guc_logger: Refactor intel_guc_logger globals into structs List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: igt-dev-bounces@lists.freedesktop.org Sender: "igt-dev" List-ID: See my comments below. Regards, Zhanjun Dong On 2022-12-06 3:58 a.m., Alan Previn wrote: > Refactor all of the global variables used in intel_guc_logger > into abstractions of structures at thread level, GuC-GT level > and global level. > > While at it, remove asserts from the non primary thread to ensure > process cleanup doesn't get stuck. > > Signed-off-by: Alan Previn > --- > tools/intel_guc_logger.c | 458 ++++++++++++++++++++++++--------------- > 1 file changed, 279 insertions(+), 179 deletions(-) > > diff --git a/tools/intel_guc_logger.c b/tools/intel_guc_logger.c > index 4a991127..356cde59 100644 > --- a/tools/intel_guc_logger.c > +++ b/tools/intel_guc_logger.c > @@ -48,12 +48,12 @@ > #define PAGE_SIZE 4096 > #endif > > -#define DEFAULT_OUTPUT_FILE_NAME "guc_log_dump.dat" > - > #define GLR_LOGLEVEL_NAME "guc_log_level" > #define GLR_CTL_NAME "guc_log_relay_ctl" > #define GLR_CHANNEL_NAME "guc_log_relay_chan0" > > +#define DEFAULT_OUTPUT_FILE_NAME "guc_log_dump" /*.dat suffic added later*/ > +#define DEFAULT_GUCLOG_VERBOSITY 3 /* by default capture logs at max verbosity */ > #define DEFAULT_SUBBUF_COUNT (4 * 8) > /* default to kernel built-in: * > * 4 x 8 subbuf regions * > @@ -64,25 +64,54 @@ > * 8K -> GuC crash dump * > * 64K -> log events buffer * > */ > - > -int drm_fd; > -char *read_buffer; > -char *out_filename; > -int poll_timeout = 2; /* by default 2ms timeout */ > -pthread_mutex_t mutex; > -pthread_t flush_thread; > -int verbosity_level = 3; /* by default capture logs at max verbosity */ > -uint32_t produced, consumed; > -uint64_t total_bytes_written; > -int subbuf_count; > -int subbuf_size; > -int ctl_fd, relay_fd, outfile_fd = -1; > -uint32_t test_duration, max_filesize; > -pthread_cond_t underflow_cond, overflow_cond; > -bool stop_logging, discard_oldlogs, capturing_stopped; > -char *gucfspath; > - > -static void get_guc_subbuf_info(void) > +#define DEFAULT_POLL_TIMEOUT 2 /* default timeout of 2ms */ > +#define DEFAULT_MAX_OUTPUT_SIZE MB(4 * 1024) /* default to 4 GB max file size */ > + > +enum relay_cmd { > + RELAY_CMD_DISABLE = 0, > + RELAY_CMD_ENABLE = 1, > + RELAY_CMD_FLUSH = 2, > +}; > + > +struct guc_t { > + int gt_id; > + char *fspath; > + int control_fd; > + int relaychan; > + int outfd; > + char *readbuf; > + int subbuf_count; > + int subbuf_size; > + uint64_t total_bytes_written; > + pthread_mutex_t mutex; > + pthread_t flush_thread; > + pthread_cond_t underflow_cond; > + pthread_cond_t overflow_cond; > + int64_t produced; > + int64_t consumed; > + bool stop_logging; > + bool capturing_stopped; > +}; > + > +struct global_t { > + int drmfd; > + int verbosity; > + char *out_filename; > + uint64_t max_filesize; > + uint32_t test_duration; > + int poll_timeout; > + bool discard_oldlogs; > +}; > + > +struct thread_t { > + struct global_t *global; > + struct guc_t *guc; > +}; > + > +/* only global instance needed for killing threads from main's signal handler */ > +struct thread_t *gbl_thread_handle; > + > +static void get_guc_subbuf_info(struct thread_t *tdata) > { > int fd, ret, j; > char *path; > @@ -92,9 +121,9 @@ static void get_guc_subbuf_info(void) > uint64_t tmp[2] = {DEFAULT_SUBBUF_SIZE, DEFAULT_SUBBUF_COUNT}; > > for (j = 0; j < 2; j++) { > - igt_assert_neq(asprintf(&path, "%s/%s", gucfspath, dbg_fs_names[j]), -1); > + igt_assert_neq(asprintf(&path, "%s/%s", tdata->guc->fspath, dbg_fs_names[j]), -1); > igt_info("Opening subbuf path %s\n", path); > - fd = igt_debugfs_open(drm_fd, path, O_RDONLY); > + fd = igt_debugfs_open(tdata->global->drmfd, path, O_RDONLY); > free(path); > igt_assert_f(fd >= 0, "couldn't open the GuC log relay-subbuf file\n"); > ret = read(fd, outstr, sizeof(outstr) - 1); > @@ -103,35 +132,36 @@ static void get_guc_subbuf_info(void) > tmp[j] = atoll(outstr); > close(fd); > } > - subbuf_size = tmp[0]; > - subbuf_count = tmp[1]; > + tdata->guc->subbuf_size = tmp[0]; > + tdata->guc->subbuf_count = tmp[1]; > igt_info("Debugfs retrieved subbuf info: size=%d, count=%d\n", > - subbuf_size, subbuf_count); > + tdata->guc->subbuf_size, tdata->guc->subbuf_count); > } > > -static void guc_log_verbosity(bool enable, int log_level) > +static void guc_log_verbosity(struct thread_t *tdata, bool enable) > { > char *str; > int loglevelfd; > uint64_t val; > int ret; > > - igt_assert_neq(asprintf(&str, "%s/%s", gucfspath, GLR_LOGLEVEL_NAME), -1); > + igt_assert_neq(asprintf(&str, "%s/%s", tdata->guc->fspath, GLR_LOGLEVEL_NAME), -1); > igt_info("Opening log level -> %s\n", str); > - loglevelfd = igt_debugfs_open(drm_fd, str, O_WRONLY); > + loglevelfd = igt_debugfs_open(tdata->global->drmfd, str, O_WRONLY); > free(str); > igt_assert_f(loglevelfd >= 0, "couldn't open the GuC log level file\n"); > > /* > * i915 expects GuC log level to be specified as: > * 0: disabled > - * 1: enabled (verbosity level 0 = min) > - * 2: enabled (verbosity level 1) > - * 3: enabled (verbosity level 2) > - * 4: enabled (verbosity level 3 = max) > + * 1: enabled (non-verbose mode) > + * 2: GuC verbosity level 0 > + * 3: GuC verbosity level 1 > + * 4: GuC verbosity level 2 > + * 5: GuC verbosity level 3 > + * intel_guc_logger takes input range of 0..3 that maps to 2..5 above. > */ > - val = enable ? log_level + 1 : 0; > - > + val = enable ? tdata->global->verbosity + 2 : 0; > ret = asprintf(&str, "0x%" PRIx64, val); > igt_assert_neq(ret, -1); > ret = write(loglevelfd, str, ret); > @@ -142,40 +172,37 @@ static void guc_log_verbosity(bool enable, int log_level) > close(loglevelfd); > } > > -static void guc_log_control(bool enable, uint32_t log_level) > +static void guc_log_control(struct thread_t *tdata, enum relay_cmd cmd) > { > char *str; > - uint64_t val = 0; > int ret; > > - if (enable) { > - igt_assert_neq(asprintf(&str, "%s/%s", gucfspath, GLR_CTL_NAME), -1); > + igt_assert_f((cmd >= 0 && cmd <= 2), "Invalid GuC-log-control cmd!\n"); > + > + if (cmd == RELAY_CMD_ENABLE) { > + igt_assert_neq(asprintf(&str, "%s/%s", tdata->guc->fspath, GLR_CTL_NAME), -1); > igt_info("Opening control file -> %s\n", str); > - ctl_fd = igt_debugfs_open(drm_fd, str, O_WRONLY); > + tdata->guc->control_fd = igt_debugfs_open(tdata->global->drmfd, str, O_WRONLY); > free(str); > - igt_assert_f(ctl_fd >= 0, "couldn't open the GuC log relay-ctl file\n"); > - val = 1; > + igt_assert_f(tdata->guc->control_fd >= 0, "Can't open GuC log relay-ctl file\n"); > } > > - /* > - * i915 expects relay logging controls: > - * 1 : open + enable relay logging > - * 2 : flush > - * 0 : disable relay logging + close > - */ > - if (ctl_fd) { > - ret = asprintf(&str, "0x%" PRIx64, val); > + if (tdata->guc->control_fd) { > + ret = asprintf(&str, "0x%" PRIx64, (unsigned long)cmd); Why don't use typical int or unsigned int for max compatibility? > igt_assert_neq(ret, -1); > - ret = write(ctl_fd, str, ret); > + ret = write(tdata->guc->control_fd, str, ret); > free(str); > - igt_assert_f(ret > 0, "couldn't write to the log control file\n"); > - } > + igt_assert_f(ret > 0, "couldn't set cmd-%u on log control file\n", cmd); > > - guc_log_verbosity(enable, log_level); > + if (cmd == RELAY_CMD_ENABLE) > + guc_log_verbosity(tdata, true); > + } > > - if (!enable) { > + if (cmd == RELAY_CMD_DISABLE) { > igt_info("Closing control file\n"); > - close(ctl_fd); > + guc_log_verbosity(tdata, false); > + close(tdata->guc->control_fd); > + tdata->guc->control_fd = 0; > } > } > > @@ -183,68 +210,82 @@ static void int_sig_handler(int sig) > { > igt_info("received signal %d\n", sig); > > - stop_logging = true; > + if (!gbl_thread_handle) > + return; > + > + if (gbl_thread_handle[0].guc) > + gbl_thread_handle[0].guc->stop_logging = true; > } > > -static void pull_leftover_data(void) > +static void pull_leftover_data(struct thread_t *tdata) > { > + struct guc_t *guc = tdata->guc; > unsigned int bytes_read = 0; > + int subbuf_size = guc->subbuf_size; > int ret; > > do { > - /* Read the logs from relay buffer */ > - ret = read(relay_fd, read_buffer, subbuf_size); > + /* Read the logs from relay channel buffer */ > + ret = read(guc->relaychan, guc->readbuf, subbuf_size); > if (!ret) > break; > - > - igt_assert_f(ret > 0, "failed to read from the GuC log file\n"); > - igt_assert_f(ret == subbuf_size, "invalid read from relay file\n"); > - > + if (ret < 0) { > + igt_warn("failed leftover-read from GuC GT-%d relay-channel\n", > + guc->gt_id); > + break; > + } > + if (ret != subbuf_size) > + igt_warn("invalid leftover-size from GuC GT-%d relay-channel\n", > + guc->gt_id); > bytes_read += ret; > - > - if (outfile_fd >= 0) { > - ret = write(outfile_fd, read_buffer, subbuf_size); > - igt_assert_f(ret == subbuf_size, "couldn't dump the logs in a file\n"); > - total_bytes_written += ret; > + if (guc->outfd >= 0) { > + ret = write(guc->outfd, guc->readbuf, subbuf_size); > + if (ret != subbuf_size) > + igt_warn("Couldn't dump leftover logs to file\n"); > + guc->total_bytes_written += ret; > } > } while(1); > > - igt_debug("%u bytes flushed\n", bytes_read); > + igt_debug("%u bytes flushed from GuC GT-%d\n", bytes_read, guc->gt_id); > } > > -static int num_filled_bufs(void) > +static int num_filled_bufs(struct guc_t *guc) > { > - return (produced - consumed); > + return (guc->produced - guc->consumed); > } > > -static void pull_data(void) > +static void pull_data(struct thread_t *tdata) > { > char *ptr; > int ret; > + struct guc_t *guc = tdata->guc; > + int subbuf_size = guc->subbuf_size; > > - pthread_mutex_lock(&mutex); > - while (num_filled_bufs() >= subbuf_count) { > - igt_debug("overflow, will wait, produced %u, consumed %u\n", produced, consumed); > + pthread_mutex_lock(&guc->mutex); > + while (num_filled_bufs(guc) >= guc->subbuf_count) { > + igt_debug("overflow, will wait, produced %ld, consumed %ld\n", > + guc->produced, guc->consumed); > /* Stall the main thread in case of overflow, as there are no > * buffers available to store the new logs, otherwise there > * could be corruption if both threads work on the same buffer. > */ > - pthread_cond_wait(&overflow_cond, &mutex); > + pthread_cond_wait(&guc->overflow_cond, &guc->mutex); > }; > - pthread_mutex_unlock(&mutex); > + pthread_mutex_unlock(&guc->mutex); > > - ptr = read_buffer + (produced % subbuf_count) * subbuf_size; > + ptr = guc->readbuf + (guc->produced % guc->subbuf_count) * subbuf_size; > > - /* Read the logs from relay buffer */ > - ret = read(relay_fd, ptr, subbuf_size); > + /* Read the logs from relay channel buffer */ > + ret = read(guc->relaychan, ptr, subbuf_size); > igt_assert_f(ret >= 0, "failed to read from the GuC log file\n"); > - igt_assert_f(!ret || ret == subbuf_size, "invalid read from relay file\n"); > + igt_assert_f(!ret || ret <= subbuf_size, "invalid read from relay file\n"); > > if (ret) { > - pthread_mutex_lock(&mutex); > - produced++; > - pthread_cond_signal(&underflow_cond); > - pthread_mutex_unlock(&mutex); > + pthread_mutex_lock(&guc->mutex); > + guc->produced++; > + pthread_cond_signal(&guc->underflow_cond); > + pthread_mutex_unlock(&guc->mutex); > + igt_info("read %d KB from relay file\n", (ret / 1024)); > } else { > /* Occasionally (very rare) read from the relay file returns no > * data, albeit the polling done prior to read call indicated > @@ -257,56 +298,74 @@ static void pull_data(void) > static void *flusher(void *arg) > { > char *ptr; > - int ret; > + int ret, subbuf_size; > + struct thread_t *tdata = (struct thread_t *)arg; > + struct global_t *gbl; > + struct guc_t *guc; > + > + igt_assert_f(tdata, "Flusher didn't receive thread context ptr!\n"); > + gbl = tdata->global; > + guc = tdata->guc; > + subbuf_size = guc->subbuf_size; > > igt_debug("execution started of flusher thread\n"); > > do { > - pthread_mutex_lock(&mutex); > - while (!num_filled_bufs()) { > + pthread_mutex_lock(&guc->mutex); > + while (!num_filled_bufs(guc)) { > /* Exit only after completing the flush of all the filled > * buffers as User would expect that all logs captured up > * till the point of interruption/exit are written out to > * the disk file. > */ > - if (capturing_stopped) { > + if (guc->capturing_stopped) { > igt_debug("flusher to exit now\n"); > - pthread_mutex_unlock(&mutex); > + pthread_mutex_unlock(&guc->mutex); > return NULL; > } > - pthread_cond_wait(&underflow_cond, &mutex); > + pthread_cond_wait(&guc->underflow_cond, &guc->mutex); > }; > - pthread_mutex_unlock(&mutex); > - > - ptr = read_buffer + (consumed % subbuf_count) * subbuf_size; > + pthread_mutex_unlock(&guc->mutex); > > - ret = write(outfile_fd, ptr, subbuf_size); > - igt_assert_f(ret == subbuf_size, "couldn't dump the logs in a file\n"); > + ptr = guc->readbuf + (guc->consumed % guc->subbuf_count) * subbuf_size; > > - total_bytes_written += ret; > - if (max_filesize && (total_bytes_written > MB(max_filesize))) { > - igt_debug("reached the target of %" PRIu64 " bytes\n", MB(max_filesize)); > - stop_logging = true; > + ret = write(guc->outfd, ptr, subbuf_size); > + if (ret < 0) { > + igt_warn("Dump to file failed with err %d, stopping!\n", ret); > + guc->stop_logging = true; > + } else if (!ret) { > + igt_warn("Dump to file flushed zero bytes!\n"); > + } else { > + if (ret != subbuf_size) > + igt_warn("Dump size mismatch = %d!\n", ret); > + guc->total_bytes_written += ret; > + igt_info("wrote %d KB out to dat file\n", (ret / 1024)); > + if (gbl->max_filesize && guc->total_bytes_written > > + MB(gbl->max_filesize)) { > + igt_debug("reached the target of %" PRIu64 " bytes\n", > + MB(gbl->max_filesize)); > + guc->stop_logging = true; > + } > + pthread_mutex_lock(&guc->mutex); > + guc->consumed++; > + pthread_cond_signal(&guc->overflow_cond); > + pthread_mutex_unlock(&guc->mutex); > } > - > - pthread_mutex_lock(&mutex); > - consumed++; > - pthread_cond_signal(&overflow_cond); > - pthread_mutex_unlock(&mutex); > } while(1); > > return NULL; > } > > -static void init_flusher_thread(void) > +static void init_flusher_thread(struct thread_t *tdata) > { > - struct sched_param thread_sched; > - pthread_attr_t p_attr; > + struct sched_param thread_sched; > + pthread_attr_t p_attr; > + struct guc_t *guc = tdata->guc; > int ret; > > - pthread_cond_init(&underflow_cond, NULL); > - pthread_cond_init(&overflow_cond, NULL); > - pthread_mutex_init(&mutex, NULL); > + pthread_cond_init(&guc->underflow_cond, NULL); > + pthread_cond_init(&guc->overflow_cond, NULL); > + pthread_mutex_init(&guc->mutex, NULL); > > ret = pthread_attr_init(&p_attr); > igt_assert_f(ret == 0, "error obtaining default thread attributes\n"); > @@ -325,22 +384,22 @@ static void init_flusher_thread(void) > ret = pthread_attr_setschedparam(&p_attr, &thread_sched); > igt_assert_f(ret == 0, "couldn't set thread priority\n"); > > - ret = pthread_create(&flush_thread, &p_attr, flusher, NULL); > + ret = pthread_create(&guc->flush_thread, &p_attr, flusher, tdata); > igt_assert_f(ret == 0, "thread creation failed\n"); > > ret = pthread_attr_destroy(&p_attr); > igt_assert_f(ret == 0, "error destroying thread attributes\n"); > } > > -static void open_relay_file(void) > +static void open_relay_file(struct thread_t *tdata) > { > char *path; > > - igt_assert_neq(asprintf(&path, "%s/%s", gucfspath, GLR_CHANNEL_NAME), -1); > + igt_assert_neq(asprintf(&path, "%s/%s", tdata->guc->fspath, GLR_CHANNEL_NAME), -1); > igt_info("Opening this path -> %s\n", path); > - relay_fd = igt_debugfs_open(drm_fd, path, O_RDONLY); > + tdata->guc->relaychan = igt_debugfs_open(tdata->global->drmfd, path, O_RDONLY); > free(path); > - igt_assert_f(relay_fd >= 0, "couldn't open the GuC log relay-channel file\n"); > + igt_assert_f(tdata->guc->relaychan >= 0, "couldn't open the GuC log relay-channel file\n"); > > /* Purge the old/boot-time logs from the relay buffer. > * This is more for Val team's requirement, where they have to first > @@ -349,29 +408,39 @@ static void open_relay_file(void) > * wait for the new data, at that point benchmark can be launched from > * a different shell. > */ > - if (discard_oldlogs) > - pull_leftover_data(); > + if (tdata->global->discard_oldlogs) > + pull_leftover_data(tdata); > } > > -static void open_output_file(void) > +static void open_output_file(struct thread_t *tdata) > { > + char *path; > + > /* Use Direct IO mode for the output file, as the data written is not > * supposed to be accessed again, this saves a copy of data from App's > * buffer to kernel buffer (Page cache). Due to no buffering on kernel > * side, data is flushed out to disk faster and more buffering can be > * done on the logger side to hide the disk IO latency. > */ > - outfile_fd = open(out_filename ? : DEFAULT_OUTPUT_FILE_NAME, > - O_CREAT | O_WRONLY | O_TRUNC | O_DIRECT, > - 0440); > - igt_assert_f(outfile_fd >= 0, "couldn't open the output file\n"); > + if (tdata->global->out_filename) { > + igt_assert_neq(asprintf(&path, "%s_GT%d.dat", tdata->global->out_filename, > + tdata->guc->gt_id), -1); > + } else { > + igt_assert_neq(asprintf(&path, "%s_GT%d.dat", DEFAULT_OUTPUT_FILE_NAME, > + tdata->guc->gt_id), -1); > + } > + > + tdata->guc->outfd = open(path, O_CREAT | O_WRONLY | O_TRUNC | O_DIRECT, 0440); > + igt_assert_f(tdata->guc->outfd >= 0, "couldn't open the output file\n"); > > - free(out_filename); > + igt_info("Creating output GuC-log-file: %s\n", path); > + free(path); > } > > -static void init_main_thread(void) > +static void init_main_thread(struct thread_t *tdata) > { > struct sched_param thread_sched; > + struct guc_t *guc = tdata->guc; > int ret; > > /* Run the main thread at highest priority to ensure that it always > @@ -390,55 +459,60 @@ static void init_main_thread(void) > igt_assert_f(0, "SIGALRM handler registration failed\n"); > > /* Need an aligned pointer for direct IO */ > - ret = posix_memalign((void **)&read_buffer, PAGE_SIZE, subbuf_count * subbuf_size); > + ret = posix_memalign((void **)&guc->readbuf, PAGE_SIZE, > + (guc->subbuf_count * guc->subbuf_size)); > igt_assert_f(ret == 0, "couldn't allocate the read buffer\n"); > > /* Keep the pages locked in RAM, avoid page fault overhead */ > - ret = mlock(read_buffer, subbuf_count * subbuf_size); > + ret = mlock(guc->readbuf, (guc->subbuf_count * guc->subbuf_size)); > igt_assert_f(ret == 0, "failed to lock memory\n"); > > /* Enable the logging, it may not have been enabled from boot and so > * the relay file also wouldn't have been created. > */ > - guc_log_control(true, verbosity_level); > - > - open_relay_file(); > - open_output_file(); > + guc_log_control(tdata, RELAY_CMD_ENABLE); > + open_relay_file(tdata); > + open_output_file(tdata); > } > > -static int parse_options(int opt, int opt_index, void *data) > +static int parse_options(int opt, int opt_index, void *ptr) > { > + struct global_t *data = (struct global_t *)ptr; > + > + igt_assert(data); > igt_debug("opt %c optarg %s\n", opt, optarg); > > switch(opt) { > case 'v': > - verbosity_level = atoi(optarg); > - igt_assert_f(verbosity_level >= 0 && verbosity_level <= 3, "invalid input for -v option\n"); > - igt_debug("verbosity level to be used is %d\n", verbosity_level); > + data->verbosity = atoi(optarg); > + igt_assert_f(data->verbosity >= 0 && data->verbosity <= 3, > + "invalid input for -v option\n"); > + igt_debug("verbosity level to be used is %d\n", data->verbosity); > break; > case 'o': > - out_filename = strdup(optarg); > - igt_assert_f(out_filename, "Couldn't allocate the o/p filename\n"); > - igt_debug("logs to be stored in file %s\n", out_filename); > + data->out_filename = strdup(optarg); > + igt_assert_f(data->out_filename, "Couldn't allocate the o/p filename\n"); > + igt_debug("logs to be stored in file %s_G[GuC-ID]\n", data->out_filename); > break; > case 't': > - test_duration = atoi(optarg); > - igt_assert_f(test_duration > 0, "invalid input for -t option\n"); > - igt_debug("logger to run for %d second\n", test_duration); > + data->test_duration = atoi(optarg); > + igt_assert_f(data->test_duration > 0, "invalid input for -t option\n"); > + igt_debug("logger to run for %d second\n", data->test_duration); > break; > case 'p': > - poll_timeout = atoi(optarg); > - igt_assert_f(poll_timeout != 0, "invalid input for -p option\n"); > - if (poll_timeout > 0) > - igt_debug("polling to be done with %d millisecond timeout\n", poll_timeout); > + data->poll_timeout = atoi(optarg); > + igt_assert_f(data->poll_timeout != 0, "invalid input for -p option\n"); > + if (data->poll_timeout > 0) > + igt_debug("polling to be done with %d millisecond timeout\n", > + data->poll_timeout); > break; > case 's': > - max_filesize = atoi(optarg); > - igt_assert_f(max_filesize > 0, "invalid input for -s option\n"); > - igt_debug("max allowed size of the output file is %d MB\n", max_filesize); > + data->max_filesize = atoll(optarg); > + igt_assert_f(data->max_filesize > 0, "invalid input for -s option\n"); > + igt_debug("max allowed size of the output file is %lu MB\n", data->max_filesize); > break; > case 'd': > - discard_oldlogs = true; > + data->discard_oldlogs = true; > igt_debug("old/boot-time logs will be discarded\n"); > break; How about unsupported option(s)? > } > @@ -446,7 +520,7 @@ static int parse_options(int opt, int opt_index, void *data) > return 0; > } > > -static void process_command_line(int argc, char **argv) > +static void process_command_line(int argc, char **argv, struct global_t *data) > { > static struct option long_options[] = { > {"verbosity", required_argument, 0, 'v'}, > @@ -467,23 +541,39 @@ static void process_command_line(int argc, char **argv) > " -d --discard discard the old/boot-time logs before entering into the capture loop\n"; > > igt_simple_init_parse_opts(&argc, argv, "v:o:b:t:p:s:d", long_options, > - help, parse_options, NULL); > + help, parse_options, data); > } > > int main(int argc, char **argv) > { > + struct global_t gbldata; > + /* For now, just one thread collecting logs from any single GuC source */ > + struct guc_t gucdata[1]; /* only GT0 for now */ > + struct thread_t thread[1]; > struct pollfd relay_poll_fd; > - int nfds; > - int ret; > + int nfds, ret; > > - drm_fd = drm_open_driver(DRIVER_INTEL); > - igt_assert(drm_fd != -1); > - igt_assert_neq(asprintf(&gucfspath, "gt0/uc"), -1); > + /* setup global context */ > + memset(&gbldata, 0, sizeof(gbldata)); > + gbldata.verbosity = DEFAULT_GUCLOG_VERBOSITY; > + gbldata.poll_timeout = DEFAULT_POLL_TIMEOUT; > + gbldata.drmfd = drm_open_driver_render(DRIVER_INTEL); > + igt_assert(gbldata.drmfd != -1); > > - get_guc_subbuf_info(); > - process_command_line(argc, argv); > + memset(&gucdata[0], 0, sizeof(struct guc_t)); > + gucdata[0].gt_id = 0; > + igt_assert_neq(asprintf(&gucdata[0].fspath, "gt/uc"), -1); Depends on platform, name could be gt/uc or gt0/uc, gt1/uc > + gucdata[0].outfd = -1; > > - init_main_thread(); > + thread[0].global = &gbldata; > + thread[0].guc = &gucdata[0]; > + get_guc_subbuf_info(&thread[0]); > + > + process_command_line(argc, argv, &gbldata); > + > + gbl_thread_handle = thread; > + > + init_main_thread(&thread[0]); > > /* Use a separate thread for flushing the logs to a file on disk. > * Main thread will buffer the data from relay file in its pool of > @@ -493,15 +583,15 @@ int main(int argc, char **argv) > * (/proc/sys/vm/dirty_ratio), kernel starts blocking the processes > * doing the file writes. > */ > - init_flusher_thread(); > + init_flusher_thread(&thread[0]); > > - relay_poll_fd.fd = relay_fd; > + relay_poll_fd.fd = thread[0].guc->relaychan; > relay_poll_fd.events = POLLIN; > relay_poll_fd.revents = 0; > > nfds = 1; /* only one fd to poll */ > > - alarm(test_duration); /* Start the alarm */ > + alarm(gbldata.test_duration); /* Start the alarm */ > > do { > /* Wait/poll for the new data to be available, relay doesn't > @@ -515,7 +605,7 @@ int main(int argc, char **argv) > * succession (less than a jiffy gap between 2 flush interrupts) > * causing relay to run out of sub buffers to store new logs. > */ > - ret = poll(&relay_poll_fd, nfds, poll_timeout); > + ret = poll(&relay_poll_fd, nfds, gbldata.poll_timeout); > if (ret < 0) { > if (errno == EINTR) > break; > @@ -526,24 +616,34 @@ int main(int argc, char **argv) > if (!relay_poll_fd.revents) > continue; > > - pull_data(); > - } while (!stop_logging); > + pull_data(&thread[0]); > + } while (!thread[0].guc->stop_logging); > > /* Pause logging on the GuC side */ > - guc_log_control(false, 0); > + guc_log_control(&thread[0], RELAY_CMD_FLUSH); > + guc_log_control(&thread[0], RELAY_CMD_DISABLE); > > /* Signal flusher thread to make an exit */ > - capturing_stopped = 1; > - pthread_cond_signal(&underflow_cond); > - pthread_join(flush_thread, NULL); > - > - pull_leftover_data(); > - igt_info("total bytes written %" PRIu64 "\n", total_bytes_written); > - > - free(read_buffer); > - close(relay_fd); > - close(outfile_fd); > - free(gucfspath); > - close(drm_fd); > + thread[0].guc->capturing_stopped = 1; > + pthread_cond_signal(&thread[0].guc->underflow_cond); > + pthread_join(thread[0].guc->flush_thread, NULL); > + pull_leftover_data(&thread[0]); > + igt_info("total bytes written %" PRIu64 "\n", thread[0].guc->total_bytes_written); > + > + if (gucdata[0].outfd) > + close(gucdata[0].outfd); > + if (gucdata[0].relaychan > 0) > + close(gucdata[0].relaychan); > + if (gucdata[0].control_fd > 0) > + close(gucdata[0].control_fd); > + if (gucdata[0].readbuf) > + free(gucdata[0].readbuf); > + if (gucdata[0].fspath) > + free(gucdata[0].fspath); > + > + if (gbldata.out_filename) > + free(gbldata.out_filename); > + close(gbldata.drmfd); > + > igt_exit(); > }