fn prepare_data_collector()

in src/data/perf_stat.rs [150:315]


    fn prepare_data_collector(&mut self, params: &CollectorParams) -> Result<()> {
        let num_cpus = match unsafe { libc::sysconf(libc::_SC_NPROCESSORS_ONLN as libc::c_int) } {
            -1 => {
                warn!("Could not get the number of cpus in the system with sysconf.");
                return Err(PDError::CollectorPMUCPUError.into());
            }
            ret => ret as usize,
        };
        let mut cpu_groups: Vec<CpuCtrGroup> = Vec::new();

        cfg_if::cfg_if! {
            if #[cfg(target_arch = "aarch64")] {
                let mut perf_list = to_events(arm64_perf_list::GRV_EVENTS)?;
            } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
                let cpu_info = crate::data::utils::get_cpu_info()?;
                let platform_specific_counter: &[u8];
                let base: &[u8];

                /* Get Vendor Specific Perf events */
                if cpu_info.vendor == "GenuineIntel" {
                    base = x86_perf_list::INTEL_EVENTS;

                    /* Get Model specific events */
                    platform_specific_counter = match cpu_info.model_name.as_str() {
                        "Intel(R) Xeon(R) Platinum 8375C CPU @ 2.90GHz" => x86_perf_list::ICX_CTRS,
                        "Intel(R) Xeon(R) Platinum 8488C" => x86_perf_list::SPR_CTRS,
                        _ => &[0; 1],
                    };
                } else if cpu_info.vendor == "AuthenticAMD" {
                    warn!("Event multiplexing may result in bad PMU data."); //TODO: mitigate bad PMU data on AMD instances
                    base = x86_perf_list::AMD_EVENTS;

                    /* Get Model specific events */
                    platform_specific_counter = match cpu_info.model_name.get(..13).unwrap_or_default() {
                        "AMD EPYC 9R14" => x86_perf_list::GENOA_CTRS,
                        "AMD EPYC 7R13" => x86_perf_list::MILAN_CTRS,
                        _ => &[0; 1],
                    };
                } else {
                    return Err(PDError::CollectorPerfUnsupportedCPU.into());
                }

                let mut perf_list = form_events_map(base, platform_specific_counter)?;
            } else {
                return Err(PDError::CollectorPerfUnsupportedCPU.into());
            }
        }
        if let Some(custom_file) = &params.pmu_config {
            let f = File::open(custom_file)?;
            let user_provided_list: Result<Vec<NamedCtr>, serde_json::Error> =
                serde_json::from_reader(&f);
            match user_provided_list {
                Ok(ul) => {
                    info!("Using custom PMU configuration provided by user.");
                    perf_list = ul;
                }
                Err(_) => {
                    error!("User provided PMU configuration is invalid. Aperf exiting...");
                    std::process::exit(1);
                }
            }
        }
        /* Write the pmu_config being used to the recorded data */
        let perf_list_pathbuf = PathBuf::from(&params.data_dir).join("pmu_config.json");
        let f = File::create(&perf_list_pathbuf)?;
        serde_json::to_writer_pretty(f, &perf_list)?;
        for cpu in 0..num_cpus {
            for named_ctr in &perf_list {
                let perf_group = Builder::new(Software::DUMMY)
                    .read_format(
                        ReadFormat::GROUP
                            | ReadFormat::TOTAL_TIME_ENABLED
                            | ReadFormat::TOTAL_TIME_RUNNING
                            | ReadFormat::ID,
                    )
                    .any_pid()
                    .one_cpu(cpu)
                    .build_group();

                let group = match perf_group {
                    Err(e) => {
                        match e.kind() {
                            ErrorKind::PermissionDenied => {
                                warn!("Set /proc/sys/kernel/perf_event_paranoid to 0")
                            }
                            ErrorKind::NotFound => warn!("Instance does not expose Perf counters"),
                            _ => warn!("Unknown error when trying to use Perf API"),
                        }
                        return Err(e.into());
                    }
                    Ok(g) => g,
                };
                let mut cpu_group = CpuCtrGroup {
                    cpu: cpu as u64,
                    name: named_ctr.name.to_string(),
                    nr_ctrs: Vec::new(),
                    dr_ctrs: Vec::new(),
                    scale: named_ctr.scale,
                    group,
                };
                for nr in &named_ctr.nrs {
                    let nr_ctr = Ctr::new(
                        nr.perf_type as u64,
                        nr.name.to_string(),
                        cpu,
                        nr.config,
                        &mut cpu_group.group,
                    );
                    match nr_ctr {
                        Err(e) => {
                            if let Some(os_error) = e.downcast_ref::<std::io::Error>() {
                                match os_error.kind() {
                                    ErrorKind::NotFound => {
                                        warn!("Instance does not expose Perf counters")
                                    }
                                    _ => match os_error.raw_os_error().unwrap() {
                                        libc::EMFILE => warn!(
                                            "Too many open files. Increase limit with `ulimit -n 65536`"
                                        ),
                                        _ => warn!("Unknown error when trying to use Perf API."),
                                    },
                                }
                                return Err(e);
                            }
                        }
                        Ok(v) => cpu_group.nr_ctr_add(v),
                    }
                }
                for dr in &named_ctr.drs {
                    let dr_ctr = Ctr::new(
                        dr.perf_type as u64,
                        dr.name.to_string(),
                        cpu,
                        dr.config,
                        &mut cpu_group.group,
                    );
                    match dr_ctr {
                        Err(e) => {
                            if let Some(os_error) = e.downcast_ref::<std::io::Error>() {
                                match os_error.kind() {
                                    ErrorKind::NotFound => {
                                        warn!("Instance does not expose Perf counters")
                                    }
                                    _ => match os_error.raw_os_error().unwrap() {
                                        libc::EMFILE => warn!(
                                            "Too many open files. Increase limit with `ulimit -n 65536`"
                                        ),
                                        _ => warn!("Unknown error when trying to use Perf API."),
                                    },
                                }
                                return Err(e);
                            }
                        }
                        Ok(v) => cpu_group.dr_ctr_add(v),
                    }
                }
                cpu_groups.push(cpu_group);
            }
        }
        for cpu_group in &mut *cpu_groups {
            cpu_group.group.reset()?;
            cpu_group.group.enable()?;
        }
        CPU_CTR_GROUPS.lock().unwrap().append(&mut cpu_groups);
        Ok(())
    }