/** * @brief Reads monitoring event data at given \a interval for \a sel_time time span * * @param cap detected PQoS capabilites */ static void monitoring_loop(const struct pqos_cap *cap) { double llc_factor = 1, mbr_factor = 1, mbl_factor = 1; unsigned mon_number = 0; int ret = PQOS_RETVAL_OK; int i = 0; if (signal(SIGINT, monitoring_ctrlc) == SIG_ERR) printf("Failed to catch SIGINT!\n"); ret = get_event_factors(cap, &llc_factor, &mbr_factor, &mbl_factor); if (ret != PQOS_RETVAL_OK) return; if (!process_mode()) mon_number = (unsigned) sel_monitor_num; else mon_number = (unsigned) sel_process_num; while (!stop_monitoring_loop) { ret = pqos_mon_poll(m_mon_grps, (unsigned)mon_number); if (ret != PQOS_RETVAL_OK) { printf("Failed to poll monitoring data!\n"); return; } if (!process_mode()) { printf(" CORE RMID LLC[KB]" " MBL[MB] MBR[MB]\n"); for (i = 0; i < sel_monitor_num; i++) { const struct pqos_event_values *pv = &m_mon_grps[i]->values; double llc = (double)pv->llc, mbr = (double)pv->mbm_remote_delta, mbl = (double)pv->mbm_local_delta; printf("%8u %8u %10.1f %10.1f %10.1f\n", m_mon_grps[i]->cores[0], m_mon_grps[i]->poll_ctx[0].rmid, llc * llc_factor, mbl * mbl_factor, mbr * mbr_factor); } } else { printf("PID LLC[KB]\n"); for (i = 0; i < sel_process_num; i++) { const struct pqos_event_values *pv = &m_mon_grps[i]->values; double llc = (double)pv->llc; printf("%6d %10.1f\n", m_mon_grps[i]->pid, llc * llc_factor); } } printf("\nPress Enter to continue or Ctrl+c to exit"); if (getchar() != '\n') break; printf("\e[1;1H\e[2J"); } }
/** * @brief Starts monitoring on selected cores/PIDs * * @param [in] cpu_info cpu information structure * @param [in] cap_mon monitoring capabilities structure * * @return Operation status * @retval 0 OK * @retval -1 error */ static int setup_monitoring(const struct pqos_cpuinfo *cpu_info, const struct pqos_capability * const cap_mon) { unsigned i; const enum pqos_mon_event perf_events = PQOS_PERF_EVENT_IPC | PQOS_PERF_EVENT_LLC_MISS; for (i = 0; (unsigned)i < cap_mon->u.mon->num_events; i++) sel_events_max |= (cap_mon->u.mon->events[i].type); /* Remove perf events IPC and LLC MISSES */ sel_events_max &= ~perf_events; if (sel_monitor_num == 0 && sel_process_num == 0) { for (i = 0; i < cpu_info->num_cores; i++) { unsigned lcore = cpu_info->cores[i].lcore; sel_monitor_core_tab[sel_monitor_num].core = lcore; sel_monitor_core_tab[sel_monitor_num].events = sel_events_max; m_mon_grps[sel_monitor_num] = malloc(sizeof(**m_mon_grps)); sel_monitor_core_tab[sel_monitor_num].pgrp = m_mon_grps[sel_monitor_num]; sel_monitor_num++; } } if (!process_mode()) { for (i = 0; i < (unsigned) sel_monitor_num; i++) { unsigned lcore = sel_monitor_core_tab[i].core; int ret; ret = pqos_mon_start(1, &lcore, sel_events_max, NULL, sel_monitor_core_tab[i].pgrp); if (ret != PQOS_RETVAL_OK) { printf("Monitoring start error on core %u," "status %d\n", lcore, ret); return ret; } } } else { for (i = 0; i < (unsigned) sel_process_num; i++) { pid_t pid = sel_monitor_pid_tab[i].pid; int ret; ret = pqos_mon_start_pid(pid, PQOS_MON_EVENT_L3_OCCUP, NULL, sel_monitor_pid_tab[i].pgrp); if (ret != PQOS_RETVAL_OK) { printf("Monitoring start error on pid %u," "status %d\n", pid, ret); return ret; } } } return PQOS_RETVAL_OK; }
/** * @brief Builds monitoring header string * * @param hdr place to store monitoring header row * @param sz_hdr available memory size for the header * @param isxml true if XML output selected * @param istext true is TEXT output selected * @param iscsv true is CSV output selected */ static void build_header_row(char *hdr, const size_t sz_hdr, const int isxml, const int istext, const int iscsv) { ASSERT(hdr != NULL && sz_hdr > 0); memset(hdr, 0, sz_hdr); if (isxml) return; if (istext) { if (!process_mode()) strncpy(hdr, " CORE IPC MISSES", sz_hdr - 1); else strncpy(hdr, " PID CORE IPC MISSES", sz_hdr - 1); if (sel_events_max & PQOS_MON_EVENT_L3_OCCUP) strncat(hdr, " LLC[KB]", sz_hdr - strlen(hdr) - 1); if (sel_events_max & PQOS_MON_EVENT_LMEM_BW) strncat(hdr, " MBL[MB/s]", sz_hdr - strlen(hdr) - 1); if (sel_events_max & PQOS_MON_EVENT_RMEM_BW) strncat(hdr, " MBR[MB/s]", sz_hdr - strlen(hdr) - 1); } if (iscsv) { if (!process_mode()) strncpy(hdr, "Time,Core,IPC,LLC Misses", sz_hdr - 1); else strncpy(hdr, "Time,PID,Core,IPC,LLC Misses", sz_hdr - 1); if (sel_events_max & PQOS_MON_EVENT_L3_OCCUP) strncat(hdr, ",LLC[KB]", sz_hdr - strlen(hdr) - 1); if (sel_events_max & PQOS_MON_EVENT_LMEM_BW) strncat(hdr, ",MBL[MB/s]", sz_hdr - strlen(hdr) - 1); if (sel_events_max & PQOS_MON_EVENT_RMEM_BW) strncat(hdr, ",MBR[MB/s]", sz_hdr - strlen(hdr) - 1); } }
/** * @brief Initializes two arrays with pointers to PQoS monitoring structures * * Function does the following things: * - figures size of the array to allocate * - allocates memory for the two arrays * - initializes allocated arrays with data from core or pid table * - saves array pointers in \a parray1 and \a parray2 * - both arrays have identical content * * @param parray1 pointer to an array of pointers to PQoS monitoring structures * @param parray2 pointer to an array of pointers to PQoS monitoring structures * * @return Number of elements in each of the tables */ static unsigned get_mon_arrays(struct pqos_mon_data ***parray1, struct pqos_mon_data ***parray2) { unsigned mon_number, i; struct pqos_mon_data **p1, **p2; ASSERT(parray1 != NULL && parray2 != NULL); if (!process_mode()) mon_number = (unsigned) sel_monitor_num; else mon_number = (unsigned) sel_process_num; p1 = malloc(sizeof(p1[0]) * mon_number); p2 = malloc(sizeof(p2[0]) * mon_number); if (p1 == NULL || p2 == NULL) { if (p1) free(p1); if (p2) free(p2); printf("Error with memory allocation"); exit(EXIT_FAILURE); } for (i = 0; i < mon_number; i++) { if (!process_mode()) p1[i] = sel_monitor_core_tab[i].pgrp; else p1[i] = sel_monitor_pid_tab[i].pgrp; p2[i] = p1[i]; } *parray1 = p1; *parray2 = p2; return mon_number; }
/** * @brief Stops monitoring on selected cores * */ static void stop_monitoring(void) { unsigned i, mon_number = 0; if (!process_mode()) mon_number = (unsigned) sel_monitor_num; else mon_number = (unsigned) sel_process_num; for (i = 0; i < mon_number; i++) { int ret; ret = pqos_mon_stop(m_mon_grps[i]); if (ret != PQOS_RETVAL_OK) printf("Monitoring stop error!\n"); free(m_mon_grps[i]); } }
int main() { init(); init_positions(); init_buttons(); while(1) { if(ButtonPressed(BUTTON3, PA2)) { change_mode(); } process_mode(currentMode); } return 0; }
/** * @brief Prints row of monitoring data in csv format * * @param fp pointer to file to direct output * @param time pointer to string containing time data * @param mon_data pointer to pqos_mon_data structure * @param llc LLC occupancy data * @param mbr remote memory bandwidth data * @param mbl local memory bandwidth data */ static void print_csv_row(FILE *fp, char *time, struct pqos_mon_data *mon_data, const double llc, const double mbr, const double mbl) { const size_t sz_data = 128; char data[sz_data]; size_t offset = 0; ASSERT(fp != NULL); ASSERT(time != NULL); ASSERT(mon_data != NULL); memset(data, 0, sz_data); offset += fillin_csv_column(llc, data + offset, sz_data - offset, mon_data->event & PQOS_MON_EVENT_L3_OCCUP, sel_events_max & PQOS_MON_EVENT_L3_OCCUP); offset += fillin_csv_column(mbl, data + offset, sz_data - offset, mon_data->event & PQOS_MON_EVENT_LMEM_BW, sel_events_max & PQOS_MON_EVENT_LMEM_BW); offset += fillin_csv_column(mbr, data + offset, sz_data - offset, mon_data->event & PQOS_MON_EVENT_RMEM_BW, sel_events_max & PQOS_MON_EVENT_RMEM_BW); if (!process_mode()) fprintf(fp, "%s,%s,%.2f,%llu%s\n", time, (char *)mon_data->context, mon_data->values.ipc, (unsigned long long)mon_data->values.llc_misses_delta, data); else fprintf(fp, "%s,%u,%s,%.2f,%llu%s\n", time, mon_data->pid, "N/A", mon_data->values.ipc, (unsigned long long)mon_data->values.llc_misses_delta, data); }
/** * @brief Prints row of monitoring data in text format * * @param fp pointer to file to direct output * @param mon_data pointer to pqos_mon_data structure * @param llc LLC occupancy data * @param mbr remote memory bandwidth data * @param mbl local memory bandwidth data */ static void print_text_row(FILE *fp, struct pqos_mon_data *mon_data, const double llc, const double mbr, const double mbl) { const size_t sz_data = 128; char data[sz_data]; size_t offset = 0; ASSERT(fp != NULL); ASSERT(mon_data != NULL); memset(data, 0, sz_data); offset += fillin_text_column(llc, data + offset, sz_data - offset, mon_data->event & PQOS_MON_EVENT_L3_OCCUP, sel_events_max & PQOS_MON_EVENT_L3_OCCUP); offset += fillin_text_column(mbl, data + offset, sz_data - offset, mon_data->event & PQOS_MON_EVENT_LMEM_BW, sel_events_max & PQOS_MON_EVENT_LMEM_BW); offset += fillin_text_column(mbr, data + offset, sz_data - offset, mon_data->event & PQOS_MON_EVENT_RMEM_BW, sel_events_max & PQOS_MON_EVENT_RMEM_BW); if (!process_mode()) fprintf(fp, "\n%8.8s %5.2f %6uk%s", (char *)mon_data->context, mon_data->values.ipc, (unsigned)mon_data->values.llc_misses_delta/1000, data); else fprintf(fp, "\n%6u %6s %6.2f %6uk%s", mon_data->pid, "N/A", mon_data->values.ipc, (unsigned)mon_data->values.llc_misses_delta/1000, data); }
void monitor_stop(void) { int i; if (!process_mode()) for (i = 0; i < sel_monitor_num; i++) { int ret = pqos_mon_stop(sel_monitor_core_tab[i].pgrp); if (ret != PQOS_RETVAL_OK) printf("Monitoring stop error!\n"); free(sel_monitor_core_tab[i].desc); free(sel_monitor_core_tab[i].cores); free(sel_monitor_core_tab[i].pgrp); } else for (i = 0; i < sel_process_num; i++) { int ret = pqos_mon_stop(sel_monitor_pid_tab[i].pgrp); if (ret != PQOS_RETVAL_OK) printf("Monitoring stop error!\n"); free(sel_monitor_pid_tab[i].pgrp); } }
int monitor_setup(const struct pqos_cpuinfo *cpu_info, const struct pqos_capability const *cap_mon) { unsigned i; int ret; enum pqos_mon_event all_core_evts = 0, all_pid_evts = 0; const enum pqos_mon_event evt_all = (enum pqos_mon_event)PQOS_MON_EVENT_ALL; ASSERT(sel_monitor_num >= 0); ASSERT(sel_process_num >= 0); /** * Check output file type */ if (sel_output_type == NULL) sel_output_type = strdup("text"); if (sel_output_type == NULL) { printf("Memory allocation error!\n"); return -1; } if (strcasecmp(sel_output_type, "text") != 0 && strcasecmp(sel_output_type, "xml") != 0 && strcasecmp(sel_output_type, "csv") != 0) { printf("Invalid selection of file output type '%s'!\n", sel_output_type); return -1; } /** * Set up file descriptor for monitored data */ if (sel_output_file == NULL) { fp_monitor = stdout; } else { if (strcasecmp(sel_output_type, "xml") == 0 || strcasecmp(sel_output_type, "csv") == 0) fp_monitor = fopen(sel_output_file, "w+"); else fp_monitor = fopen(sel_output_file, "a"); if (fp_monitor == NULL) { perror("Monitoring output file open error:"); printf("Error opening '%s' output file!\n", sel_output_file); return -1; } if (strcasecmp(sel_output_type, "xml") == 0) fprintf(fp_monitor, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" "%s\n", xml_root_open); } /** * get all available events on this platform */ for (i = 0; i < cap_mon->u.mon->num_events; i++) { struct pqos_monitor *mon = &cap_mon->u.mon->events[i]; all_core_evts |= mon->type; if (mon->pid_support) all_pid_evts |= mon->type; } /** * If no cores and events selected through command line * by default let's monitor all cores */ if (sel_monitor_num == 0 && sel_process_num == 0) { sel_events_max = all_core_evts; for (i = 0; i < cpu_info->num_cores; i++) { unsigned lcore = cpu_info->cores[i].lcore; uint64_t core = (uint64_t)lcore; struct core_group *pg = &sel_monitor_core_tab[sel_monitor_num]; if ((unsigned) sel_monitor_num >= DIM(sel_monitor_core_tab)) break; ret = set_cgrp(pg, uinttostr(lcore), &core, 1); if (ret != 0) { printf("Core group setup error!\n"); exit(EXIT_FAILURE); } pg->events = sel_events_max; pg->pgrp = malloc(sizeof(*pg->pgrp)); if (pg->pgrp == NULL) { printf("Error with memory allocation!\n"); exit(EXIT_FAILURE); } sel_monitor_num++; } } if (sel_process_num > 0 && sel_monitor_num > 0) { printf("Monitoring start error, process and core" " tracking can not be done simultaneously\n"); return -1; } if (!process_mode()) { /** * Make calls to pqos_mon_start - track cores */ for (i = 0; i < (unsigned)sel_monitor_num; i++) { struct core_group *cg = &sel_monitor_core_tab[i]; /* check if all available events were selected */ if (cg->events == evt_all) { cg->events = all_core_evts; sel_events_max |= all_core_evts; } else { if (all_core_evts & PQOS_PERF_EVENT_IPC) cg->events |= PQOS_PERF_EVENT_IPC; if (all_core_evts & PQOS_PERF_EVENT_LLC_MISS) cg->events |= PQOS_PERF_EVENT_LLC_MISS; } ret = pqos_mon_start(cg->num_cores, cg->cores, cg->events, (void *)cg->desc, cg->pgrp); ASSERT(ret == PQOS_RETVAL_OK); /** * The error raised also if two instances of PQoS * attempt to use the same core id. */ if (ret != PQOS_RETVAL_OK) { if (ret == PQOS_RETVAL_PERF_CTR) printf("Use -r option to start " "monitoring anyway.\n"); printf("Monitoring start error on core(s) " "%s, status %d\n", cg->desc, ret); return -1; } } } else { /** * Make calls to pqos_mon_start_pid - track PIDs */ for (i = 0; i < (unsigned)sel_process_num; i++) { struct pid_group *pg = &sel_monitor_pid_tab[i]; /* check if all available events were selected */ if (pg->events == evt_all) { pg->events = all_pid_evts; sel_events_max |= all_pid_evts; } else { if (all_pid_evts & PQOS_PERF_EVENT_IPC) pg->events |= PQOS_PERF_EVENT_IPC; if (all_pid_evts & PQOS_PERF_EVENT_LLC_MISS) pg->events |= PQOS_PERF_EVENT_LLC_MISS; } ret = pqos_mon_start_pid(sel_monitor_pid_tab[i].pid, sel_monitor_pid_tab[i].events, NULL, sel_monitor_pid_tab[i].pgrp); ASSERT(ret == PQOS_RETVAL_OK); /** * Any problem with monitoring the process? */ if (ret != PQOS_RETVAL_OK) { printf("PID %d monitoring start error," "status %d\n", sel_monitor_pid_tab[i].pid, ret); return -1; } } } return 0; }
void monitor_loop(const struct pqos_cap *cap) { #define TERM_MIN_NUM_LINES 3 const long interval = (long)sel_mon_interval * 100000LL; /* interval in [us] units */ double llc_factor = 1, mbr_factor = 1, mbl_factor = 1; struct timeval tv_start; int ret = PQOS_RETVAL_OK; const int istty = isatty(fileno(fp_monitor)); const int istext = !strcasecmp(sel_output_type, "text"); const int isxml = !strcasecmp(sel_output_type, "xml"); const int iscsv = !strcasecmp(sel_output_type, "csv"); const size_t sz_header = 128; char header[sz_header]; unsigned mon_number = 0, display_num = 0; struct pqos_mon_data **mon_data = NULL, **mon_grps = NULL; if ((!istext) && (!isxml) && (!iscsv)) { printf("Invalid selection of output file type '%s'!\n", sel_output_type); return; } ret = get_event_factors(cap, &llc_factor, &mbr_factor, &mbl_factor); if (ret != PQOS_RETVAL_OK) { printf("Error in retrieving monitoring scale factors!\n"); return; } mon_number = get_mon_arrays(&mon_grps, &mon_data); display_num = mon_number; /** * Capture ctrl-c to gracefully stop the loop */ if (signal(SIGINT, monitoring_ctrlc) == SIG_ERR) printf("Failed to catch SIGINT!\n"); if (signal(SIGHUP, monitoring_ctrlc) == SIG_ERR) printf("Failed to catch SIGHUP!\n"); if (istty) { struct winsize w; unsigned max_lines = 0; if (ioctl(fileno(fp_monitor), TIOCGWINSZ, &w) != -1) { max_lines = w.ws_row; if (max_lines < TERM_MIN_NUM_LINES) max_lines = TERM_MIN_NUM_LINES; } if ((display_num + TERM_MIN_NUM_LINES - 1) > max_lines) display_num = max_lines - TERM_MIN_NUM_LINES + 1; } /** * Coefficient to display the data as MB / s */ const double coeff = 10.0 / (double)sel_mon_interval; mbr_factor = mbr_factor * coeff; mbl_factor = mbl_factor * coeff; /** * Build the header */ build_header_row(header, sz_header, isxml, istext, iscsv); if (iscsv) fprintf(fp_monitor, "%s\n", header); gettimeofday(&tv_start, NULL); while (!stop_monitoring_loop) { struct timeval tv_s, tv_e; struct tm *ptm = NULL; unsigned i = 0; struct timespec req, rem; long usec_start = 0, usec_end = 0, usec_diff = 0; char cb_time[64]; gettimeofday(&tv_s, NULL); ret = pqos_mon_poll(mon_grps, mon_number); if (ret != PQOS_RETVAL_OK) { printf("Failed to poll monitoring data!\n"); free(mon_grps); free(mon_data); return; } memcpy(mon_data, mon_grps, mon_number * sizeof(mon_grps[0])); if (sel_mon_top_like) qsort(mon_data, mon_number, sizeof(mon_data[0]), mon_qsort_llc_cmp_desc); else if (!process_mode()) qsort(mon_data, mon_number, sizeof(mon_data[0]), mon_qsort_coreid_cmp_asc); /** * Get time string */ ptm = localtime(&tv_s.tv_sec); if (ptm != NULL) strftime(cb_time, sizeof(cb_time) - 1, "%Y-%m-%d %H:%M:%S", ptm); else strncpy(cb_time, "error", sizeof(cb_time) - 1); if (istty && istext) fprintf(fp_monitor, "\033[2J" /* Clear screen */ "\033[0;0H"); /* move to position 0:0 */ if (istext) fprintf(fp_monitor, "TIME %s\n%s", cb_time, header); for (i = 0; i < display_num; i++) { const struct pqos_event_values *pv = &mon_data[i]->values; double llc = (double)pv->llc * llc_factor; double mbr = (double)pv->mbm_remote_delta * mbr_factor; double mbl = (double)pv->mbm_local_delta * mbl_factor; if (istext) print_text_row(fp_monitor, mon_data[i], llc, mbr, mbl); if (isxml) print_xml_row(fp_monitor, cb_time, mon_data[i], llc, mbr, mbl); if (iscsv) print_csv_row(fp_monitor, cb_time, mon_data[i], llc, mbr, mbl); } if (!istty && istext) fputs("\n", fp_monitor); fflush(fp_monitor); gettimeofday(&tv_e, NULL); if (stop_monitoring_loop) break; /** * Calculate microseconds to the nearest measurement interval */ usec_start = ((long)tv_s.tv_usec) + ((long)tv_s.tv_sec * 1000000L); usec_end = ((long)tv_e.tv_usec) + ((long)tv_e.tv_sec * 1000000L); usec_diff = usec_end - usec_start; if (usec_diff < interval) { memset(&rem, 0, sizeof(rem)); memset(&req, 0, sizeof(req)); req.tv_sec = (interval - usec_diff) / 1000000L; req.tv_nsec = ((interval - usec_diff) % 1000000L) * 1000L; if (nanosleep(&req, &rem) == -1) { /** * nanosleep() interrupted by a signal */ if (stop_monitoring_loop) break; req = rem; memset(&rem, 0, sizeof(rem)); nanosleep(&req, &rem); } } if (sel_timeout >= 0) { gettimeofday(&tv_e, NULL); if ((tv_e.tv_sec - tv_start.tv_sec) > sel_timeout) break; } } if (isxml) fprintf(fp_monitor, "%s\n", xml_root_close); if (istty) fputs("\n\n", fp_monitor); free(mon_grps); free(mon_data); }
/** * @brief Prints row of monitoring data in xml format * * @param fp pointer to file to direct output * @param time pointer to string containing time data * @param mon_data pointer to pqos_mon_data structure * @param llc LLC occupancy data * @param mbr remote memory bandwidth data * @param mbl local memory bandwidth data */ static void print_xml_row(FILE *fp, char *time, struct pqos_mon_data *mon_data, const double llc, const double mbr, const double mbl) { const size_t sz_data = 128; char data[sz_data]; size_t offset = 0; ASSERT(fp != NULL); ASSERT(time != NULL); ASSERT(mon_data != NULL); offset += fillin_xml_column(llc, data + offset, sz_data - offset, mon_data->event & PQOS_MON_EVENT_L3_OCCUP, sel_events_max & PQOS_MON_EVENT_L3_OCCUP, "l3_occupancy_kB"); offset += fillin_xml_column(mbl, data + offset, sz_data - offset, mon_data->event & PQOS_MON_EVENT_LMEM_BW, sel_events_max & PQOS_MON_EVENT_LMEM_BW, "mbm_local_MB"); offset += fillin_xml_column(mbr, data + offset, sz_data - offset, mon_data->event & PQOS_MON_EVENT_RMEM_BW, sel_events_max & PQOS_MON_EVENT_RMEM_BW, "mbm_remote_MB"); if (!process_mode()) fprintf(fp, "%s\n" "\t<time>%s</time>\n" "\t<core>%s</core>\n" "\t<ipc>%.2f</ipc>\n" "\t<llc_misses>%llu</llc_misses>\n" "%s" "%s\n", xml_child_open, time, (char *)mon_data->context, mon_data->values.ipc, (unsigned long long)mon_data->values.llc_misses_delta, data, xml_child_close); else fprintf(fp, "%s\n" "\t<time>%s</time>\n" "\t<pid>%u</pid>\n" "\t<core>%s</core>\n" "\t<ipc>%.2f</ipc>\n" "\t<llc_misses>%llu</llc_misses>\n" "%s" "%s\n", xml_child_open, time, mon_data->pid, "N/A", mon_data->values.ipc, (unsigned long long)mon_data->values.llc_misses_delta, data, xml_child_close); }