Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Memory bandwidth monitoring and allocation library
0004  *
0005  * Copyright (C) 2018 Intel Corporation
0006  *
0007  * Authors:
0008  *    Sai Praneeth Prakhya <sai.praneeth.prakhya@intel.com>,
0009  *    Fenghua Yu <fenghua.yu@intel.com>
0010  */
0011 #include "resctrl.h"
0012 
0013 #define UNCORE_IMC      "uncore_imc"
0014 #define READ_FILE_NAME      "events/cas_count_read"
0015 #define WRITE_FILE_NAME     "events/cas_count_write"
0016 #define DYN_PMU_PATH        "/sys/bus/event_source/devices"
0017 #define SCALE           0.00006103515625
0018 #define MAX_IMCS        20
0019 #define MAX_TOKENS      5
0020 #define READ            0
0021 #define WRITE           1
0022 #define CON_MON_MBM_LOCAL_BYTES_PATH                \
0023     "%s/%s/mon_groups/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
0024 
0025 #define CON_MBM_LOCAL_BYTES_PATH        \
0026     "%s/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
0027 
0028 #define MON_MBM_LOCAL_BYTES_PATH        \
0029     "%s/mon_groups/%s/mon_data/mon_L3_%02d/mbm_local_bytes"
0030 
0031 #define MBM_LOCAL_BYTES_PATH            \
0032     "%s/mon_data/mon_L3_%02d/mbm_local_bytes"
0033 
0034 #define CON_MON_LCC_OCCUP_PATH      \
0035     "%s/%s/mon_groups/%s/mon_data/mon_L3_%02d/llc_occupancy"
0036 
0037 #define CON_LCC_OCCUP_PATH      \
0038     "%s/%s/mon_data/mon_L3_%02d/llc_occupancy"
0039 
0040 #define MON_LCC_OCCUP_PATH      \
0041     "%s/mon_groups/%s/mon_data/mon_L3_%02d/llc_occupancy"
0042 
0043 #define LCC_OCCUP_PATH          \
0044     "%s/mon_data/mon_L3_%02d/llc_occupancy"
0045 
0046 struct membw_read_format {
0047     __u64 value;         /* The value of the event */
0048     __u64 time_enabled;  /* if PERF_FORMAT_TOTAL_TIME_ENABLED */
0049     __u64 time_running;  /* if PERF_FORMAT_TOTAL_TIME_RUNNING */
0050     __u64 id;            /* if PERF_FORMAT_ID */
0051 };
0052 
0053 struct imc_counter_config {
0054     __u32 type;
0055     __u64 event;
0056     __u64 umask;
0057     struct perf_event_attr pe;
0058     struct membw_read_format return_value;
0059     int fd;
0060 };
0061 
0062 static char mbm_total_path[1024];
0063 static int imcs;
0064 static struct imc_counter_config imc_counters_config[MAX_IMCS][2];
0065 
0066 void membw_initialize_perf_event_attr(int i, int j)
0067 {
0068     memset(&imc_counters_config[i][j].pe, 0,
0069            sizeof(struct perf_event_attr));
0070     imc_counters_config[i][j].pe.type = imc_counters_config[i][j].type;
0071     imc_counters_config[i][j].pe.size = sizeof(struct perf_event_attr);
0072     imc_counters_config[i][j].pe.disabled = 1;
0073     imc_counters_config[i][j].pe.inherit = 1;
0074     imc_counters_config[i][j].pe.exclude_guest = 0;
0075     imc_counters_config[i][j].pe.config =
0076         imc_counters_config[i][j].umask << 8 |
0077         imc_counters_config[i][j].event;
0078     imc_counters_config[i][j].pe.sample_type = PERF_SAMPLE_IDENTIFIER;
0079     imc_counters_config[i][j].pe.read_format =
0080         PERF_FORMAT_TOTAL_TIME_ENABLED | PERF_FORMAT_TOTAL_TIME_RUNNING;
0081 }
0082 
0083 void membw_ioctl_perf_event_ioc_reset_enable(int i, int j)
0084 {
0085     ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_RESET, 0);
0086     ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_ENABLE, 0);
0087 }
0088 
0089 void membw_ioctl_perf_event_ioc_disable(int i, int j)
0090 {
0091     ioctl(imc_counters_config[i][j].fd, PERF_EVENT_IOC_DISABLE, 0);
0092 }
0093 
0094 /*
0095  * get_event_and_umask: Parse config into event and umask
0096  * @cas_count_cfg:  Config
0097  * @count:      iMC number
0098  * @op:         Operation (read/write)
0099  */
0100 void get_event_and_umask(char *cas_count_cfg, int count, bool op)
0101 {
0102     char *token[MAX_TOKENS];
0103     int i = 0;
0104 
0105     strcat(cas_count_cfg, ",");
0106     token[0] = strtok(cas_count_cfg, "=,");
0107 
0108     for (i = 1; i < MAX_TOKENS; i++)
0109         token[i] = strtok(NULL, "=,");
0110 
0111     for (i = 0; i < MAX_TOKENS; i++) {
0112         if (!token[i])
0113             break;
0114         if (strcmp(token[i], "event") == 0) {
0115             if (op == READ)
0116                 imc_counters_config[count][READ].event =
0117                 strtol(token[i + 1], NULL, 16);
0118             else
0119                 imc_counters_config[count][WRITE].event =
0120                 strtol(token[i + 1], NULL, 16);
0121         }
0122         if (strcmp(token[i], "umask") == 0) {
0123             if (op == READ)
0124                 imc_counters_config[count][READ].umask =
0125                 strtol(token[i + 1], NULL, 16);
0126             else
0127                 imc_counters_config[count][WRITE].umask =
0128                 strtol(token[i + 1], NULL, 16);
0129         }
0130     }
0131 }
0132 
0133 static int open_perf_event(int i, int cpu_no, int j)
0134 {
0135     imc_counters_config[i][j].fd =
0136         perf_event_open(&imc_counters_config[i][j].pe, -1, cpu_no, -1,
0137                 PERF_FLAG_FD_CLOEXEC);
0138 
0139     if (imc_counters_config[i][j].fd == -1) {
0140         fprintf(stderr, "Error opening leader %llx\n",
0141             imc_counters_config[i][j].pe.config);
0142 
0143         return -1;
0144     }
0145 
0146     return 0;
0147 }
0148 
0149 /* Get type and config (read and write) of an iMC counter */
0150 static int read_from_imc_dir(char *imc_dir, int count)
0151 {
0152     char cas_count_cfg[1024], imc_counter_cfg[1024], imc_counter_type[1024];
0153     FILE *fp;
0154 
0155     /* Get type of iMC counter */
0156     sprintf(imc_counter_type, "%s%s", imc_dir, "type");
0157     fp = fopen(imc_counter_type, "r");
0158     if (!fp) {
0159         perror("Failed to open imc counter type file");
0160 
0161         return -1;
0162     }
0163     if (fscanf(fp, "%u", &imc_counters_config[count][READ].type) <= 0) {
0164         perror("Could not get imc type");
0165         fclose(fp);
0166 
0167         return -1;
0168     }
0169     fclose(fp);
0170 
0171     imc_counters_config[count][WRITE].type =
0172                 imc_counters_config[count][READ].type;
0173 
0174     /* Get read config */
0175     sprintf(imc_counter_cfg, "%s%s", imc_dir, READ_FILE_NAME);
0176     fp = fopen(imc_counter_cfg, "r");
0177     if (!fp) {
0178         perror("Failed to open imc config file");
0179 
0180         return -1;
0181     }
0182     if (fscanf(fp, "%s", cas_count_cfg) <= 0) {
0183         perror("Could not get imc cas count read");
0184         fclose(fp);
0185 
0186         return -1;
0187     }
0188     fclose(fp);
0189 
0190     get_event_and_umask(cas_count_cfg, count, READ);
0191 
0192     /* Get write config */
0193     sprintf(imc_counter_cfg, "%s%s", imc_dir, WRITE_FILE_NAME);
0194     fp = fopen(imc_counter_cfg, "r");
0195     if (!fp) {
0196         perror("Failed to open imc config file");
0197 
0198         return -1;
0199     }
0200     if  (fscanf(fp, "%s", cas_count_cfg) <= 0) {
0201         perror("Could not get imc cas count write");
0202         fclose(fp);
0203 
0204         return -1;
0205     }
0206     fclose(fp);
0207 
0208     get_event_and_umask(cas_count_cfg, count, WRITE);
0209 
0210     return 0;
0211 }
0212 
0213 /*
0214  * A system can have 'n' number of iMC (Integrated Memory Controller)
0215  * counters, get that 'n'. For each iMC counter get it's type and config.
0216  * Also, each counter has two configs, one for read and the other for write.
0217  * A config again has two parts, event and umask.
0218  * Enumerate all these details into an array of structures.
0219  *
0220  * Return: >= 0 on success. < 0 on failure.
0221  */
0222 static int num_of_imcs(void)
0223 {
0224     char imc_dir[512], *temp;
0225     unsigned int count = 0;
0226     struct dirent *ep;
0227     int ret;
0228     DIR *dp;
0229 
0230     dp = opendir(DYN_PMU_PATH);
0231     if (dp) {
0232         while ((ep = readdir(dp))) {
0233             temp = strstr(ep->d_name, UNCORE_IMC);
0234             if (!temp)
0235                 continue;
0236 
0237             /*
0238              * imc counters are named as "uncore_imc_<n>", hence
0239              * increment the pointer to point to <n>. Note that
0240              * sizeof(UNCORE_IMC) would count for null character as
0241              * well and hence the last underscore character in
0242              * uncore_imc'_' need not be counted.
0243              */
0244             temp = temp + sizeof(UNCORE_IMC);
0245 
0246             /*
0247              * Some directories under "DYN_PMU_PATH" could have
0248              * names like "uncore_imc_free_running", hence, check if
0249              * first character is a numerical digit or not.
0250              */
0251             if (temp[0] >= '0' && temp[0] <= '9') {
0252                 sprintf(imc_dir, "%s/%s/", DYN_PMU_PATH,
0253                     ep->d_name);
0254                 ret = read_from_imc_dir(imc_dir, count);
0255                 if (ret) {
0256                     closedir(dp);
0257 
0258                     return ret;
0259                 }
0260                 count++;
0261             }
0262         }
0263         closedir(dp);
0264         if (count == 0) {
0265             perror("Unable find iMC counters!\n");
0266 
0267             return -1;
0268         }
0269     } else {
0270         perror("Unable to open PMU directory!\n");
0271 
0272         return -1;
0273     }
0274 
0275     return count;
0276 }
0277 
0278 static int initialize_mem_bw_imc(void)
0279 {
0280     int imc, j;
0281 
0282     imcs = num_of_imcs();
0283     if (imcs <= 0)
0284         return imcs;
0285 
0286     /* Initialize perf_event_attr structures for all iMC's */
0287     for (imc = 0; imc < imcs; imc++) {
0288         for (j = 0; j < 2; j++)
0289             membw_initialize_perf_event_attr(imc, j);
0290     }
0291 
0292     return 0;
0293 }
0294 
0295 /*
0296  * get_mem_bw_imc:  Memory band width as reported by iMC counters
0297  * @cpu_no:     CPU number that the benchmark PID is binded to
0298  * @bw_report:      Bandwidth report type (reads, writes)
0299  *
0300  * Memory B/W utilized by a process on a socket can be calculated using
0301  * iMC counters. Perf events are used to read these counters.
0302  *
0303  * Return: = 0 on success. < 0 on failure.
0304  */
0305 static int get_mem_bw_imc(int cpu_no, char *bw_report, float *bw_imc)
0306 {
0307     float reads, writes, of_mul_read, of_mul_write;
0308     int imc, j, ret;
0309 
0310     /* Start all iMC counters to log values (both read and write) */
0311     reads = 0, writes = 0, of_mul_read = 1, of_mul_write = 1;
0312     for (imc = 0; imc < imcs; imc++) {
0313         for (j = 0; j < 2; j++) {
0314             ret = open_perf_event(imc, cpu_no, j);
0315             if (ret)
0316                 return -1;
0317         }
0318         for (j = 0; j < 2; j++)
0319             membw_ioctl_perf_event_ioc_reset_enable(imc, j);
0320     }
0321 
0322     sleep(1);
0323 
0324     /* Stop counters after a second to get results (both read and write) */
0325     for (imc = 0; imc < imcs; imc++) {
0326         for (j = 0; j < 2; j++)
0327             membw_ioctl_perf_event_ioc_disable(imc, j);
0328     }
0329 
0330     /*
0331      * Get results which are stored in struct type imc_counter_config
0332      * Take over flow into consideration before calculating total b/w
0333      */
0334     for (imc = 0; imc < imcs; imc++) {
0335         struct imc_counter_config *r =
0336             &imc_counters_config[imc][READ];
0337         struct imc_counter_config *w =
0338             &imc_counters_config[imc][WRITE];
0339 
0340         if (read(r->fd, &r->return_value,
0341              sizeof(struct membw_read_format)) == -1) {
0342             perror("Couldn't get read b/w through iMC");
0343 
0344             return -1;
0345         }
0346 
0347         if (read(w->fd, &w->return_value,
0348              sizeof(struct membw_read_format)) == -1) {
0349             perror("Couldn't get write bw through iMC");
0350 
0351             return -1;
0352         }
0353 
0354         __u64 r_time_enabled = r->return_value.time_enabled;
0355         __u64 r_time_running = r->return_value.time_running;
0356 
0357         if (r_time_enabled != r_time_running)
0358             of_mul_read = (float)r_time_enabled /
0359                     (float)r_time_running;
0360 
0361         __u64 w_time_enabled = w->return_value.time_enabled;
0362         __u64 w_time_running = w->return_value.time_running;
0363 
0364         if (w_time_enabled != w_time_running)
0365             of_mul_write = (float)w_time_enabled /
0366                     (float)w_time_running;
0367         reads += r->return_value.value * of_mul_read * SCALE;
0368         writes += w->return_value.value * of_mul_write * SCALE;
0369     }
0370 
0371     for (imc = 0; imc < imcs; imc++) {
0372         close(imc_counters_config[imc][READ].fd);
0373         close(imc_counters_config[imc][WRITE].fd);
0374     }
0375 
0376     if (strcmp(bw_report, "reads") == 0) {
0377         *bw_imc = reads;
0378         return 0;
0379     }
0380 
0381     if (strcmp(bw_report, "writes") == 0) {
0382         *bw_imc = writes;
0383         return 0;
0384     }
0385 
0386     *bw_imc = reads + writes;
0387     return 0;
0388 }
0389 
0390 void set_mbm_path(const char *ctrlgrp, const char *mongrp, int resource_id)
0391 {
0392     if (ctrlgrp && mongrp)
0393         sprintf(mbm_total_path, CON_MON_MBM_LOCAL_BYTES_PATH,
0394             RESCTRL_PATH, ctrlgrp, mongrp, resource_id);
0395     else if (!ctrlgrp && mongrp)
0396         sprintf(mbm_total_path, MON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
0397             mongrp, resource_id);
0398     else if (ctrlgrp && !mongrp)
0399         sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
0400             ctrlgrp, resource_id);
0401     else if (!ctrlgrp && !mongrp)
0402         sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH, RESCTRL_PATH,
0403             resource_id);
0404 }
0405 
0406 /*
0407  * initialize_mem_bw_resctrl:   Appropriately populate "mbm_total_path"
0408  * @ctrlgrp:            Name of the control monitor group (con_mon grp)
0409  * @mongrp:         Name of the monitor group (mon grp)
0410  * @cpu_no:         CPU number that the benchmark PID is binded to
0411  * @resctrl_val:        Resctrl feature (Eg: mbm, mba.. etc)
0412  */
0413 static void initialize_mem_bw_resctrl(const char *ctrlgrp, const char *mongrp,
0414                       int cpu_no, char *resctrl_val)
0415 {
0416     int resource_id;
0417 
0418     if (get_resource_id(cpu_no, &resource_id) < 0) {
0419         perror("Could not get resource_id");
0420         return;
0421     }
0422 
0423     if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)))
0424         set_mbm_path(ctrlgrp, mongrp, resource_id);
0425 
0426     if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) {
0427         if (ctrlgrp)
0428             sprintf(mbm_total_path, CON_MBM_LOCAL_BYTES_PATH,
0429                 RESCTRL_PATH, ctrlgrp, resource_id);
0430         else
0431             sprintf(mbm_total_path, MBM_LOCAL_BYTES_PATH,
0432                 RESCTRL_PATH, resource_id);
0433     }
0434 }
0435 
0436 /*
0437  * Get MBM Local bytes as reported by resctrl FS
0438  * For MBM,
0439  * 1. If con_mon grp and mon grp are given, then read from con_mon grp's mon grp
0440  * 2. If only con_mon grp is given, then read from con_mon grp
0441  * 3. If both are not given, then read from root con_mon grp
0442  * For MBA,
0443  * 1. If con_mon grp is given, then read from it
0444  * 2. If con_mon grp is not given, then read from root con_mon grp
0445  */
0446 static int get_mem_bw_resctrl(unsigned long *mbm_total)
0447 {
0448     FILE *fp;
0449 
0450     fp = fopen(mbm_total_path, "r");
0451     if (!fp) {
0452         perror("Failed to open total bw file");
0453 
0454         return -1;
0455     }
0456     if (fscanf(fp, "%lu", mbm_total) <= 0) {
0457         perror("Could not get mbm local bytes");
0458         fclose(fp);
0459 
0460         return -1;
0461     }
0462     fclose(fp);
0463 
0464     return 0;
0465 }
0466 
0467 pid_t bm_pid, ppid;
0468 
0469 void ctrlc_handler(int signum, siginfo_t *info, void *ptr)
0470 {
0471     kill(bm_pid, SIGKILL);
0472     umount_resctrlfs();
0473     tests_cleanup();
0474     ksft_print_msg("Ending\n\n");
0475 
0476     exit(EXIT_SUCCESS);
0477 }
0478 
0479 /*
0480  * print_results_bw:    the memory bandwidth results are stored in a file
0481  * @filename:       file that stores the results
0482  * @bm_pid:     child pid that runs benchmark
0483  * @bw_imc:     perf imc counter value
0484  * @bw_resc:        memory bandwidth value
0485  *
0486  * Return:      0 on success. non-zero on failure.
0487  */
0488 static int print_results_bw(char *filename,  int bm_pid, float bw_imc,
0489                 unsigned long bw_resc)
0490 {
0491     unsigned long diff = fabs(bw_imc - bw_resc);
0492     FILE *fp;
0493 
0494     if (strcmp(filename, "stdio") == 0 || strcmp(filename, "stderr") == 0) {
0495         printf("Pid: %d \t Mem_BW_iMC: %f \t ", bm_pid, bw_imc);
0496         printf("Mem_BW_resc: %lu \t Difference: %lu\n", bw_resc, diff);
0497     } else {
0498         fp = fopen(filename, "a");
0499         if (!fp) {
0500             perror("Cannot open results file");
0501 
0502             return errno;
0503         }
0504         if (fprintf(fp, "Pid: %d \t Mem_BW_iMC: %f \t Mem_BW_resc: %lu \t Difference: %lu\n",
0505                 bm_pid, bw_imc, bw_resc, diff) <= 0) {
0506             fclose(fp);
0507             perror("Could not log results.");
0508 
0509             return errno;
0510         }
0511         fclose(fp);
0512     }
0513 
0514     return 0;
0515 }
0516 
0517 static void set_cmt_path(const char *ctrlgrp, const char *mongrp, char sock_num)
0518 {
0519     if (strlen(ctrlgrp) && strlen(mongrp))
0520         sprintf(llc_occup_path, CON_MON_LCC_OCCUP_PATH, RESCTRL_PATH,
0521             ctrlgrp, mongrp, sock_num);
0522     else if (!strlen(ctrlgrp) && strlen(mongrp))
0523         sprintf(llc_occup_path, MON_LCC_OCCUP_PATH, RESCTRL_PATH,
0524             mongrp, sock_num);
0525     else if (strlen(ctrlgrp) && !strlen(mongrp))
0526         sprintf(llc_occup_path, CON_LCC_OCCUP_PATH, RESCTRL_PATH,
0527             ctrlgrp, sock_num);
0528     else if (!strlen(ctrlgrp) && !strlen(mongrp))
0529         sprintf(llc_occup_path, LCC_OCCUP_PATH, RESCTRL_PATH, sock_num);
0530 }
0531 
0532 /*
0533  * initialize_llc_occu_resctrl: Appropriately populate "llc_occup_path"
0534  * @ctrlgrp:            Name of the control monitor group (con_mon grp)
0535  * @mongrp:         Name of the monitor group (mon grp)
0536  * @cpu_no:         CPU number that the benchmark PID is binded to
0537  * @resctrl_val:        Resctrl feature (Eg: cat, cmt.. etc)
0538  */
0539 static void initialize_llc_occu_resctrl(const char *ctrlgrp, const char *mongrp,
0540                     int cpu_no, char *resctrl_val)
0541 {
0542     int resource_id;
0543 
0544     if (get_resource_id(cpu_no, &resource_id) < 0) {
0545         perror("# Unable to resource_id");
0546         return;
0547     }
0548 
0549     if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)))
0550         set_cmt_path(ctrlgrp, mongrp, resource_id);
0551 }
0552 
0553 static int
0554 measure_vals(struct resctrl_val_param *param, unsigned long *bw_resc_start)
0555 {
0556     unsigned long bw_resc, bw_resc_end;
0557     float bw_imc;
0558     int ret;
0559 
0560     /*
0561      * Measure memory bandwidth from resctrl and from
0562      * another source which is perf imc value or could
0563      * be something else if perf imc event is not available.
0564      * Compare the two values to validate resctrl value.
0565      * It takes 1sec to measure the data.
0566      */
0567     ret = get_mem_bw_imc(param->cpu_no, param->bw_report, &bw_imc);
0568     if (ret < 0)
0569         return ret;
0570 
0571     ret = get_mem_bw_resctrl(&bw_resc_end);
0572     if (ret < 0)
0573         return ret;
0574 
0575     bw_resc = (bw_resc_end - *bw_resc_start) / MB;
0576     ret = print_results_bw(param->filename, bm_pid, bw_imc, bw_resc);
0577     if (ret)
0578         return ret;
0579 
0580     *bw_resc_start = bw_resc_end;
0581 
0582     return 0;
0583 }
0584 
0585 /*
0586  * resctrl_val: execute benchmark and measure memory bandwidth on
0587  *          the benchmark
0588  * @benchmark_cmd:  benchmark command and its arguments
0589  * @param:      parameters passed to resctrl_val()
0590  *
0591  * Return:      0 on success. non-zero on failure.
0592  */
0593 int resctrl_val(char **benchmark_cmd, struct resctrl_val_param *param)
0594 {
0595     char *resctrl_val = param->resctrl_val;
0596     unsigned long bw_resc_start = 0;
0597     struct sigaction sigact;
0598     int ret = 0, pipefd[2];
0599     char pipe_message = 0;
0600     union sigval value;
0601 
0602     if (strcmp(param->filename, "") == 0)
0603         sprintf(param->filename, "stdio");
0604 
0605     if (!strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR)) ||
0606         !strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR))) {
0607         ret = validate_bw_report_request(param->bw_report);
0608         if (ret)
0609             return ret;
0610     }
0611 
0612     ret = remount_resctrlfs(param->mum_resctrlfs);
0613     if (ret)
0614         return ret;
0615 
0616     /*
0617      * If benchmark wasn't successfully started by child, then child should
0618      * kill parent, so save parent's pid
0619      */
0620     ppid = getpid();
0621 
0622     if (pipe(pipefd)) {
0623         perror("# Unable to create pipe");
0624 
0625         return -1;
0626     }
0627 
0628     /*
0629      * Fork to start benchmark, save child's pid so that it can be killed
0630      * when needed
0631      */
0632     bm_pid = fork();
0633     if (bm_pid == -1) {
0634         perror("# Unable to fork");
0635 
0636         return -1;
0637     }
0638 
0639     if (bm_pid == 0) {
0640         /*
0641          * Mask all signals except SIGUSR1, parent uses SIGUSR1 to
0642          * start benchmark
0643          */
0644         sigfillset(&sigact.sa_mask);
0645         sigdelset(&sigact.sa_mask, SIGUSR1);
0646 
0647         sigact.sa_sigaction = run_benchmark;
0648         sigact.sa_flags = SA_SIGINFO;
0649 
0650         /* Register for "SIGUSR1" signal from parent */
0651         if (sigaction(SIGUSR1, &sigact, NULL))
0652             PARENT_EXIT("Can't register child for signal");
0653 
0654         /* Tell parent that child is ready */
0655         close(pipefd[0]);
0656         pipe_message = 1;
0657         if (write(pipefd[1], &pipe_message, sizeof(pipe_message)) <
0658             sizeof(pipe_message)) {
0659             perror("# failed signaling parent process");
0660             close(pipefd[1]);
0661             return -1;
0662         }
0663         close(pipefd[1]);
0664 
0665         /* Suspend child until delivery of "SIGUSR1" from parent */
0666         sigsuspend(&sigact.sa_mask);
0667 
0668         PARENT_EXIT("Child is done");
0669     }
0670 
0671     ksft_print_msg("Benchmark PID: %d\n", bm_pid);
0672 
0673     /*
0674      * Register CTRL-C handler for parent, as it has to kill benchmark
0675      * before exiting
0676      */
0677     sigact.sa_sigaction = ctrlc_handler;
0678     sigemptyset(&sigact.sa_mask);
0679     sigact.sa_flags = SA_SIGINFO;
0680     if (sigaction(SIGINT, &sigact, NULL) ||
0681         sigaction(SIGTERM, &sigact, NULL) ||
0682         sigaction(SIGHUP, &sigact, NULL)) {
0683         perror("# sigaction");
0684         ret = errno;
0685         goto out;
0686     }
0687 
0688     value.sival_ptr = benchmark_cmd;
0689 
0690     /* Taskset benchmark to specified cpu */
0691     ret = taskset_benchmark(bm_pid, param->cpu_no);
0692     if (ret)
0693         goto out;
0694 
0695     /* Write benchmark to specified control&monitoring grp in resctrl FS */
0696     ret = write_bm_pid_to_resctrl(bm_pid, param->ctrlgrp, param->mongrp,
0697                       resctrl_val);
0698     if (ret)
0699         goto out;
0700 
0701     if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) ||
0702         !strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) {
0703         ret = initialize_mem_bw_imc();
0704         if (ret)
0705             goto out;
0706 
0707         initialize_mem_bw_resctrl(param->ctrlgrp, param->mongrp,
0708                       param->cpu_no, resctrl_val);
0709     } else if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR)))
0710         initialize_llc_occu_resctrl(param->ctrlgrp, param->mongrp,
0711                         param->cpu_no, resctrl_val);
0712 
0713     /* Parent waits for child to be ready. */
0714     close(pipefd[1]);
0715     while (pipe_message != 1) {
0716         if (read(pipefd[0], &pipe_message, sizeof(pipe_message)) <
0717             sizeof(pipe_message)) {
0718             perror("# failed reading message from child process");
0719             close(pipefd[0]);
0720             goto out;
0721         }
0722     }
0723     close(pipefd[0]);
0724 
0725     /* Signal child to start benchmark */
0726     if (sigqueue(bm_pid, SIGUSR1, value) == -1) {
0727         perror("# sigqueue SIGUSR1 to child");
0728         ret = errno;
0729         goto out;
0730     }
0731 
0732     /* Give benchmark enough time to fully run */
0733     sleep(1);
0734 
0735     /* Test runs until the callback setup() tells the test to stop. */
0736     while (1) {
0737         if (!strncmp(resctrl_val, MBM_STR, sizeof(MBM_STR)) ||
0738             !strncmp(resctrl_val, MBA_STR, sizeof(MBA_STR))) {
0739             ret = param->setup(1, param);
0740             if (ret) {
0741                 ret = 0;
0742                 break;
0743             }
0744 
0745             ret = measure_vals(param, &bw_resc_start);
0746             if (ret)
0747                 break;
0748         } else if (!strncmp(resctrl_val, CMT_STR, sizeof(CMT_STR))) {
0749             ret = param->setup(1, param);
0750             if (ret) {
0751                 ret = 0;
0752                 break;
0753             }
0754             sleep(1);
0755             ret = measure_cache_vals(param, bm_pid);
0756             if (ret)
0757                 break;
0758         } else {
0759             break;
0760         }
0761     }
0762 
0763 out:
0764     kill(bm_pid, SIGKILL);
0765     umount_resctrlfs();
0766 
0767     return ret;
0768 }