Exemplo n.º 1
0
void DiskIODriver::readEvents(mxml_node_t *const) {
	// Only for use with perf
	if (!gSessionData->mPerf.isSetup()) {
		return;
	}

	setCounters(new DiskIOCounter(getCounters(), strdup("Linux_block_rq_rd"), &mReadBytes));
	setCounters(new DiskIOCounter(getCounters(), strdup("Linux_block_rq_wr"), &mWriteBytes));
}
Exemplo n.º 2
0
void NetDriver::readEvents(mxml_node_t *const) {
	// Only for use with perf
	if (!gSessionData->mPerf.isSetup()) {
		return;
	}

	setCounters(new NetCounter(getCounters(), strdup("Linux_net_rx"), &mReceiveBytes));
	setCounters(new NetCounter(getCounters(), strdup("Linux_net_tx"), &mTransmitBytes));
}
Exemplo n.º 3
0
void MemInfoDriver::readEvents(mxml_node_t *const) {
	// Only for use with perf
	if (!gSessionData.mPerf.isSetup()) {
		return;
	}

	setCounters(new MemInfoCounter(getCounters(), strdup("Linux_meminfo_memused2"), &mMemUsed));
	setCounters(new MemInfoCounter(getCounters(), strdup("Linux_meminfo_memfree"), &mMemFree));
	setCounters(new MemInfoCounter(getCounters(), strdup("Linux_meminfo_bufferram"), &mBuffers));
}
Exemplo n.º 4
0
void DiskIODriver::readEvents(mxml_node_t * const)
{
    if (access("/proc/diskstats", R_OK) == 0) {
        setCounters(new DiskIOCounter(getCounters(), "Linux_block_rq_rd", &mReadBytes));
        setCounters(new DiskIOCounter(getCounters(), "Linux_block_rq_wr", &mWriteBytes));
    }
    else {
        logg.logSetup("Linux counters\nCannot access /proc/diskstats. Disk I/O read and write counters not available.");
    }
}
Exemplo n.º 5
0
void MaliVideoDriver::marshalEnable(const MaliVideoCounterType type, char *const buf, const size_t bufsize, int &pos) {
	// size
	int numEnabled = 0;
	for (MaliVideoCounter *counter = static_cast<MaliVideoCounter *>(getCounters()); counter != NULL; counter = static_cast<MaliVideoCounter *>(counter->getNext())) {
		if (counter->isEnabled() && (counter->getType() == type)) {
			++numEnabled;
		}
	}
	Buffer::packInt(buf, bufsize, pos, numEnabled*sizeof(uint32_t));
	for (MaliVideoCounter *counter = static_cast<MaliVideoCounter *>(getCounters()); counter != NULL; counter = static_cast<MaliVideoCounter *>(counter->getNext())) {
		if (counter->isEnabled() && (counter->getType() == type)) {
			Buffer::packInt(buf, bufsize, pos, counter->getId());
		}
	}
}
Exemplo n.º 6
0
void HwmonDriver::readEvents(mxml_node_t *const) {
	int err = sensors_init(NULL);
	if (err) {
		logg->logMessage("Failed to initialize libsensors! (%d)", err);
		return;
	}
	sensors_sysfs_no_scaling = 1;

	int chip_nr = 0;
	const sensors_chip_name *chip;
	while ((chip = sensors_get_detected_chips(NULL, &chip_nr))) {
		int feature_nr = 0;
		const sensors_feature *feature;
		while ((feature = sensors_get_features(chip, &feature_nr))) {
			// Keep in sync with HwmonCounter::read
			// Can this counter be read?
			double value;
			const sensors_subfeature *const subfeature = sensors_get_subfeature(chip, feature, getInput(feature->type));
			if ((subfeature == NULL) || (sensors_get_value(chip, subfeature->number, &value) != 0)) {
				continue;
			}

			// Get the name of the counter
			int len = sensors_snprintf_chip_name(NULL, 0, chip) + 1;
			char *chip_name = new char[len];
			sensors_snprintf_chip_name(chip_name, len, chip);
			len = snprintf(NULL, 0, "hwmon_%s_%d_%d", chip_name, chip_nr, feature->number) + 1;
			char *const name = new char[len];
			snprintf(name, len, "hwmon_%s_%d_%d", chip_name, chip_nr, feature->number);
			delete [] chip_name;

			setCounters(new HwmonCounter(getCounters(), name, chip, feature));
		}
	}
}
Exemplo n.º 7
0
void HwmonDriver::writeEvents(mxml_node_t *root) const {
	root = mxmlNewElement(root, "category");
	mxmlElementSetAttr(root, "name", "hwmon");

	char buf[1024];
	for (HwmonCounter *counter = static_cast<HwmonCounter *>(getCounters()); counter != NULL; counter = static_cast<HwmonCounter *>(counter->getNext())) {
		mxml_node_t *node = mxmlNewElement(root, "event");
		mxmlElementSetAttr(node, "counter", counter->getName());
		mxmlElementSetAttr(node, "title", counter->getTitle());
		if (counter->isDuplicate()) {
			mxmlElementSetAttrf(node, "name", "%s (0x%x)", counter->getLabel(), counter->getKey());
		} else {
			mxmlElementSetAttr(node, "name", counter->getLabel());
		}
		mxmlElementSetAttr(node, "display", counter->getDisplay());
		mxmlElementSetAttr(node, "class", counter->getCounterClass());
		mxmlElementSetAttr(node, "units", counter->getUnit());
		if (counter->getModifier() != 1) {
			mxmlElementSetAttrf(node, "modifier", "%d", counter->getModifier());
		}
		if (strcmp(counter->getDisplay(), "average") == 0 || strcmp(counter->getDisplay(), "maximum") == 0) {
			mxmlElementSetAttr(node, "average_selection", "yes");
		}
		snprintf(buf, sizeof(buf), "libsensors %s sensor %s (%s)", counter->getTitle(), counter->getLabel(), counter->getName());
		mxmlElementSetAttr(node, "description", buf);
	}
}
Exemplo n.º 8
0
void FSDriver::readEvents(mxml_node_t *const xml) {
	mxml_node_t *node = xml;
	while (true) {
		node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
		if (node == NULL) {
			break;
		}
		const char *counter = mxmlElementGetAttr(node, "counter");
		if (counter == NULL) {
			continue;
		}

		if (counter[0] == '/') {
			logg->logError(__FILE__, __LINE__, "Old style filesystem counter (%s) detected, please create a new unique counter value and move the filename into the path attribute, see events-Filesystem.xml for examples", counter);
			handleException();
		}

		if (strncmp(counter, "filesystem_", 11) != 0) {
			continue;
		}

		const char *path = mxmlElementGetAttr(node, "path");
		if (path == NULL) {
			logg->logError(__FILE__, __LINE__, "The filesystem counter %s is missing the required path attribute", counter);
			handleException();
		}
		const char *regex = mxmlElementGetAttr(node, "regex");
		setCounters(new FSCounter(getCounters(), strdup(counter), strdup(path), regex));
	}
}
Exemplo n.º 9
0
nsresult txXSLTNumber::createNumber(Expr* aValueExpr, txPattern* aCountPattern,
                                    txPattern* aFromPattern, LevelType aLevel,
                                    Expr* aGroupSize, Expr* aGroupSeparator,
                                    Expr* aFormat, txIEvalContext* aContext,
                                    nsAString& aResult)
{
    aResult.Truncate();
    nsresult rv = NS_OK;

    // Parse format
    txList counters;
    nsAutoString head, tail;
    rv = getCounters(aGroupSize, aGroupSeparator, aFormat, aContext, counters,
                     head, tail);
    NS_ENSURE_SUCCESS(rv, rv);
    
    // Create list of values to format
    txList values;
    nsAutoString valueString;
    rv = getValueList(aValueExpr, aCountPattern, aFromPattern, aLevel,
                      aContext, values, valueString);
    NS_ENSURE_SUCCESS(rv, rv);

    if (!valueString.IsEmpty()) {
        aResult = valueString;

        return NS_OK;
    }

    // Create resulting string
    aResult = head;
    bool first = true;
    txListIterator valueIter(&values);
    txListIterator counterIter(&counters);
    valueIter.resetToEnd();
    int32_t value;
    txFormattedCounter* counter = 0;
    while ((value = NS_PTR_TO_INT32(valueIter.previous()))) {
        if (counterIter.hasNext()) {
            counter = (txFormattedCounter*)counterIter.next();
        }

        if (!first) {
            aResult.Append(counter->mSeparator);
        }

        counter->appendNumber(value, aResult);
        first = false;
    }
    
    aResult.Append(tail);
    
    txListIterator iter(&counters);
    while (iter.hasNext()) {
        delete (txFormattedCounter*)iter.next();
    }

    return NS_OK;
}
Exemplo n.º 10
0
bool FtraceDriver::readTracepointFormats(const uint64_t currTime, IPerfAttrsConsumer & attrsConsumer, DynBuf * const printb,
                                         DynBuf * const b)
{
    if (!gSessionData.mFtraceRaw) {
        return true;
    }

    if (!printb->printf(EVENTS_PATH "/header_page")) {
        logg.logMessage("DynBuf::printf failed");
        return false;
    }
    if (!b->read(printb->getBuf())) {
        logg.logMessage("DynBuf::read failed");
        return false;
    }
    attrsConsumer.marshalHeaderPage(currTime, b->getBuf());

    if (!printb->printf(EVENTS_PATH "/header_event")) {
        logg.logMessage("DynBuf::printf failed");
        return false;
    }
    if (!b->read(printb->getBuf())) {
        logg.logMessage("DynBuf::read failed");
        return false;
    }
    attrsConsumer.marshalHeaderEvent(currTime, b->getBuf());

    DIR *dir = opendir(EVENTS_PATH "/ftrace");
    if (dir == NULL) {
        logg.logError("Unable to open events ftrace folder");
        handleException();
    }
    struct dirent *dirent;
    while ((dirent = readdir(dir)) != NULL) {
        if (dirent->d_name[0] == '.' || dirent->d_type != DT_DIR) {
            continue;
        }
        if (!printb->printf(EVENTS_PATH "/ftrace/%s/format", dirent->d_name)) {
            logg.logMessage("DynBuf::printf failed");
            return false;
        }
        if (!b->read(printb->getBuf())) {
            logg.logMessage("DynBuf::read failed");
            return false;
        }
        attrsConsumer.marshalFormat(currTime, b->getLength(), b->getBuf());
    }
    closedir(dir);

    for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL;
            counter = static_cast<FtraceCounter *>(counter->getNext())) {
        if (!counter->isEnabled()) {
            continue;
        }
        counter->readTracepointFormat(currTime, attrsConsumer);
    }

    return true;
}
Exemplo n.º 11
0
void HwmonDriver::start() {
	for (DriverCounter *counter = getCounters(); counter != NULL; counter = counter->getNext()) {
		if (!counter->isEnabled()) {
			continue;
		}
		counter->read();
	}
}
Exemplo n.º 12
0
void DiskIODriver::start() {
	doRead();
	// Initialize previous values
	for (DriverCounter *counter = getCounters(); counter != NULL; counter = counter->getNext()) {
		if (!counter->isEnabled()) {
			continue;
		}
		counter->read();
	}
}
Exemplo n.º 13
0
int FSDriver::writeCounters(mxml_node_t *root) const {
	int count = 0;
	for (FSCounter *counter = static_cast<FSCounter *>(getCounters()); counter != NULL; counter = static_cast<FSCounter *>(counter->getNext())) {
		if (access(counter->getPath(), R_OK) == 0) {
			mxml_node_t *node = mxmlNewElement(root, "counter");
			mxmlElementSetAttr(node, "name", counter->getName());
			++count;
		}
	}

	return count;
}
Exemplo n.º 14
0
void NetDriver::start() {
	if (!doRead()) {
		logg->logError("Unable to read network stats");
		handleException();
	}
	// Initialize previous values
	for (DriverCounter *counter = getCounters(); counter != NULL; counter = counter->getNext()) {
		if (!counter->isEnabled()) {
			continue;
		}
		counter->read();
	}
}
Exemplo n.º 15
0
counter
uwinterference::getCounters(Packet *p)
{
	hdr_mac *mach = HDR_MAC(p);
	hdr_MPhy *ph = HDR_MPHY(p);

	PKT_TYPE recv_pkt_type;
	if (mach->ftype() == MF_CONTROL) {
		recv_pkt_type = CTRL;
	} else {
		recv_pkt_type = DATA;
	}
	return (getCounters(ph->rxtime, recv_pkt_type));
}
Exemplo n.º 16
0
void MaliVideoDriver::readEvents(mxml_node_t *const xml) {
	// Always create the counters as /dev/mv500 may show up after gatord starts
	mxml_node_t *node = xml;
	while (true) {
		node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
		if (node == NULL) {
			break;
		}
		const char *counter = mxmlElementGetAttr(node, "counter");
		if (counter == NULL) {
			// Ignore
		} else if (strncmp(counter, COUNTER, sizeof(COUNTER) - 1) == 0) {
			const int i = strtol(counter + sizeof(COUNTER) - 1, NULL, 10);
			setCounters(new MaliVideoCounter(getCounters(), strdup(counter), MVCT_COUNTER, i));
		} else if (strncmp(counter, EVENT, sizeof(EVENT) - 1) == 0) {
			const int i = strtol(counter + sizeof(EVENT) - 1, NULL, 10);
			setCounters(new MaliVideoCounter(getCounters(), strdup(counter), MVCT_EVENT, i));
		} else if (strncmp(counter, ACTIVITY, sizeof(ACTIVITY) - 1) == 0) {
			const int i = strtol(counter + sizeof(ACTIVITY) - 1, NULL, 10);
			setCounters(new MaliVideoCounter(getCounters(), strdup(counter), MVCT_ACTIVITY, i));
		}
	}
}
Exemplo n.º 17
0
std::vector<int> FtraceDriver::stop()
{
    lib::writeIntToFile(TRACING_PATH "/tracing_on", mTracingOn);

    for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL;
            counter = static_cast<FtraceCounter *>(counter->getNext())) {
        if (!counter->isEnabled()) {
            continue;
        }
        counter->stop();
    }

    std::vector<int> fds;
    if (gSessionData.mFtraceRaw) {
        for (FtraceReader *reader = FtraceReader::getHead(); reader != NULL; reader = reader->getNext()) {
            reader->interrupt();
            fds.push_back(reader->getPfd0());
        }
        for (FtraceReader *reader = FtraceReader::getHead(); reader != NULL; reader = reader->getNext()) {
            reader->join();
        }
    }
    return fds;
}
Exemplo n.º 18
0
void FtraceDriver::readEvents(mxml_node_t * const xml)
{
    // Check the kernel version
    struct utsname utsname;
    if (uname(&utsname) != 0) {
        logg.logError("uname failed");
        handleException();
    }

    // The perf clock was added in 3.10
    const int kernelVersion = lib::parseLinuxVersion(utsname);
    if (kernelVersion < KERNEL_VERSION(3, 10, 0)) {
        mSupported = false;
        logg.logSetup("Ftrace is disabled\nFor full ftrace functionality please upgrade to Linux 3.10 or later. With user space gator and Linux prior to 3.10, ftrace counters with the tracepoint and arg attributes will be available.");
        return;
    }
    mMonotonicRawSupport = kernelVersion >= KERNEL_VERSION(4, 2, 0);

    // Is debugfs or tracefs available?
    if (access(TRACING_PATH, R_OK) != 0) {
        mSupported = false;
        logg.logSetup("Ftrace is disabled\nUnable to locate the tracing directory");
        return;
    }

    if (geteuid() != 0) {
        mSupported = false;
        logg.logSetup("Ftrace is disabled\nFtrace is not supported when running non-root");
        return;
    }

    mSupported = true;

    mxml_node_t *node = xml;
    int count = 0;
    while (true) {
        node = mxmlFindElement(node, xml, "event", NULL, NULL, MXML_DESCEND);
        if (node == NULL) {
            break;
        }
        const char *counter = mxmlElementGetAttr(node, "counter");
        if (counter == NULL) {
            continue;
        }

        if (strncmp(counter, "ftrace_", 7) != 0) {
            continue;
        }

        const char *regex = mxmlElementGetAttr(node, "regex");
        if (regex == NULL) {
            logg.logError("The regex counter %s is missing the required regex attribute", counter);
            handleException();
        }

        const char *tracepoint = mxmlElementGetAttr(node, "tracepoint");
        const char *enable = mxmlElementGetAttr(node, "enable");
        if (enable == NULL) {
            enable = tracepoint;
        }
        if (!mUseForTracepoints && tracepoint != NULL) {
            logg.logMessage("Not using ftrace for counter %s", counter);
            continue;
        }
        if (enable != NULL) {
            char buf[1 << 10];
            snprintf(buf, sizeof(buf), EVENTS_PATH "/%s/enable", enable);
            if (access(buf, W_OK) != 0) {
                logg.logSetup("%s is disabled\n%s was not found", counter, buf);
                continue;
            }
        }

        logg.logMessage("Using ftrace for %s", counter);
        setCounters(new FtraceCounter(getCounters(), counter, enable));
        ++count;
    }

    mValues = new int64_t[2 * count];
}
Exemplo n.º 19
0
int IOCP_Send(IOCP* iocp, IOCP_KEY key, const unsigned char* buf, unsigned int len, unsigned int timeout, IOCP_Proc func, void* param)
{
	IOCP_CONTEXT* context = (IOCP_CONTEXT*)(key);
	int ret = IOCP_PENDING;
	unsigned int delay = 0;
	__int64 expectTime;

	if( !iocp->inited ) {
		return IOCP_UNINITIALIZED;
	}

	if(context->lockPtr) {
		Lock_Read(context->lockPtr);
	}
	if(context->status != IOCP_NORMAL)
	{
		ret = context->status; 
	}
	//else if(iocp->sessionTimeout(iocp, context))
	else if(IOCP_SessionTimeout(iocp, context))
	{
		ret = IOCP_SESSIONTIMEO;
	}
	else
	{
		context->writeOlp.oppType = IOCP_SEND;
		context->writeOlp.buf = (unsigned char*)(buf);
		context->writeOlp.len = len;
		context->writeOlp.timeout = timeout;
		context->writeOlp.iocpProc = func;
		context->writeOlp.param = param;
		context->writeOlp.realLen = len;

		if(context->writeOlp.speedLmt > 0 && context->writeOlp.lastCompleteCounter != 0)
		{
			expectTime = getCounters(iocp->frequency, (__int64)(context->writeOlp.transfered * 1.0 / context->writeOlp.speedLmt * 1000));
			expectTime += context->startCounter;

			if(expectTime > context->writeOlp.lastCompleteCounter)
			{
				delay = (unsigned int)(getMs(iocp->frequency, expectTime - context->writeOlp.lastCompleteCounter));
				if(delay > IOCP_MAXWAITTIME_ONSPEEDLMT)
				{
					delay = IOCP_MAXWAITTIME_ONSPEEDLMT;
					if(context->writeOlp.len > IOCP_MINBUFLEN_ONSPEEDLMT)
					{
						context->writeOlp.realLen = IOCP_MINBUFLEN_ONSPEEDLMT;
					}
				}
				else
				{
					context->writeOlp.realLen = context->writeOlp.len;
				}

			}
		}

		if(delay > 0)
		{
			context->writeOlp.oppType = IOCP_DELAY_WRITE;
			context->writeOlp.timer = 
				//TimerQueue_CreateTimer(&iocp->timerQueue, delay, iocp->delaySend, context);
				TimerQueue_CreateTimer(&iocp->timerQueue, delay, IOCP_DelaySend, context);
		}
		else
		{
			if(context->writeOlp.timeout > 0)
			{
				context->writeOlp.timer = 
					//TimerQueue_CreateTimer(&iocp->timerQueue, context->writeOlp.timeout, iocp->readTimeout, context);
					TimerQueue_CreateTimer(&iocp->timerQueue, context->writeOlp.timeout, IOCP_ReadTimeout, context);
			}

			//ret = iocp->realSend(iocp, context);
			ret = IOCP_RealSend(iocp, context);

			if( ret != IOCP_PENDING)
			{
				//iocp->cleanOlp(iocp, &context->writeOlp);
				IOCP_CleanOlp(iocp, &context->writeOlp);
			}
		}
	}
	if(context->lockPtr) {
		Lock_Unlock(context->lockPtr);
	}
	
	return ret;
}
Exemplo n.º 20
0
std::pair<std::vector<int>, bool> FtraceDriver::prepare()
{
    if (gSessionData.mFtraceRaw) {
        // Don't want the performace impact of sending all formats so gator only sends it for the enabled counters. This means other counters need to be disabled
        if (lib::writeCStringToFile(TRACING_PATH "/events/enable", "0") != 0) {
            logg.logError("Unable to turn off all events");
            handleException();
        }
    }

    for (FtraceCounter *counter = static_cast<FtraceCounter *>(getCounters()); counter != NULL;
            counter = static_cast<FtraceCounter *>(counter->getNext())) {
        if (!counter->isEnabled()) {
            continue;
        }
        counter->prepare();
    }

    if (lib::readIntFromFile(TRACING_PATH "/tracing_on", mTracingOn)) {
        logg.logError("Unable to read if ftrace is enabled");
        handleException();
    }

    if (lib::writeCStringToFile(TRACING_PATH "/tracing_on", "0") != 0) {
        logg.logError("Unable to turn ftrace off before truncating the buffer");
        handleException();
    }

    {
        int fd;
        // The below call can be slow on loaded high-core count systems.
        fd = open(TRACING_PATH "/trace", O_WRONLY | O_TRUNC | O_CLOEXEC, 0666);
        if (fd < 0) {
            logg.logError("Unable truncate ftrace buffer: %s", strerror(errno));
            handleException();
        }
        close(fd);
    }

    const char * const trace_clock_path = TRACING_PATH "/trace_clock";
    const char * const clock = mMonotonicRawSupport ? "mono_raw" : "perf";
    const char * const clock_selected = mMonotonicRawSupport ? "[mono_raw]" : "[perf]";
    const size_t max_trace_clock_file_length = 200;
    ssize_t trace_clock_file_length;
    char trace_clock_file_content[max_trace_clock_file_length + 1] = { 0 };
    bool must_switch_clock = true;
    // Only write to /trace_clock if the clock actually needs changing,
    // as changing trace_clock can be extremely expensive, especially on large
    // core count systems. The idea is that hopefully only on the first
    // capture, the trace clock needs to be changed. On subsequent captures,
    // the right clock is already being used.
    int fd = open(trace_clock_path, O_RDONLY);
    if (fd < 0) {
        logg.logError("Couldn't open %s", trace_clock_path);
        handleException();
    }
    if ((trace_clock_file_length = ::read(fd, trace_clock_file_content, max_trace_clock_file_length - 1)) < 0) {
        logg.logError("Couldn't read from %s", trace_clock_path);
        close(fd);
        handleException();
    }
    close(fd);
    trace_clock_file_content[trace_clock_file_length] = 0;
    if (::strstr(trace_clock_file_content, clock_selected)) {
        // the right clock was already selected :)
        must_switch_clock = false;
    }

    // Writing to trace_clock can be very slow on loaded high core count
    // systems.
    if (must_switch_clock && lib::writeCStringToFile(TRACING_PATH "/trace_clock", clock) != 0) {
        logg.logError("Unable to switch ftrace to the %s clock, please ensure you are running Linux %s or later", clock, mMonotonicRawSupport ? "4.2" : "3.10");
        handleException();
    }

    if (!gSessionData.mFtraceRaw) {
        const int fd = open(TRACING_PATH "/trace_pipe", O_RDONLY | O_CLOEXEC);
        if (fd < 0) {
            logg.logError("Unable to open trace_pipe");
            handleException();
        }
        return {{fd},true};
    }

    struct sigaction act;
    memset(&act, 0, sizeof(act));
    act.sa_handler = handlerUsr1;
    if (sigaction(SIGUSR1, &act, NULL) != 0) {
        logg.logError("sigaction failed");
        handleException();
    }

    pageSize = sysconf(_SC_PAGESIZE);
    if (pageSize <= 0) {
        logg.logError("sysconf PAGESIZE failed");
        handleException();
    }

    mBarrier.init(mNumberOfCores + 1);

    std::pair<std::vector<int>, bool> result {{}, false};
    for (size_t cpu = 0; cpu < mNumberOfCores; ++cpu) {
        int pfd[2];
        if (pipe2(pfd, O_CLOEXEC) != 0) {
            logg.logError("pipe2 failed, %s (%i)", strerror(errno), errno);
            handleException();
        }

        char buf[64];
        snprintf(buf, sizeof(buf), TRACING_PATH "/per_cpu/cpu%zu/trace_pipe_raw", cpu);
        const int tfd = open(buf, O_RDONLY | O_CLOEXEC);
        (new FtraceReader(&mBarrier, cpu, tfd, pfd[0], pfd[1]))->start();
        result.first.push_back(pfd[0]);
    }

    return result;
}