Skip to content
This repository was archived by the owner on Oct 12, 2022. It is now read-only.
/ druntime Public archive

Bindings to linux perf_event header.#3160

Merged
RazvanN7 merged 7 commits intodlang:masterfrom
maxhaton:performance_perf_event
Aug 27, 2021
Merged

Bindings to linux perf_event header.#3160
RazvanN7 merged 7 commits intodlang:masterfrom
maxhaton:performance_perf_event

Conversation

@maxhaton
Copy link
Member

I am working towards a uarch-level benchmarking and tracing library for phobos, so: these are bindings to perf_event.h . eBPF coming soon.

The system call perf_event_open is not included by glibc so I have included a function to call it that includes system call numbers for X86, amd64 and both varieties of ARM. The bitfields were done by including Phobos bitmanips manually - there could potentially be namespace collisions due to the extern(C) but I chose to keep it simple for now.

A simple example (Converted almost verbatim from the manpage) works fine but I am looking for a more thorough test suite (or at least one that covers most of the functions without converting hacky "kernel C" into D by hand).

import core.sys.linux.perf_event;
import core.stdc.stdio;
import core.stdc.string;
import core.stdc.stdlib;
import std.stdio : writeln;
import core.sys.posix.sys.ioctl;
import core.sys.posix.unistd;
import core.sys.linux.unistd;
extern(C)
int main(int argc, char** argv)
{
    perf_event_attr pe;
    long count;
    int fd;

    memset(&pe, 0, perf_event_attr.sizeof);
    pe.type = perf_type_id.PERF_TYPE_HARDWARE;
    pe.size = perf_event_attr.sizeof;
    pe.config = perf_hw_id.PERF_COUNT_HW_INSTRUCTIONS;
    pe.disabled = 1;
    pe.exclude_kernel = 1;
    pe.exclude_hv = 1;

    fd = cast(int) perf_event_open(&pe, 0, -1, -1, 0);
    if (fd == -1)
    {
        fprintf(stderr, "Error opening leader %llx\n", pe.config);
        exit(EXIT_FAILURE);
    }

    ioctl(fd, PERF_EVENT_IOC_RESET, 0);
    ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);

    puts("Measuring instruction count for this puts");

    ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
    read(fd, &count, long.sizeof);
    
    printf("Used %lld instructions\n", count);

    close(fd);
    return 0;
}

@dlang-bot
Copy link
Contributor

dlang-bot commented Jul 14, 2020

Thanks for your pull request, @maxhaton!

Bugzilla references

Your PR doesn't reference any Bugzilla issue.

If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.

Testing this PR locally

If you don't have a local development environment setup, you can use Digger to test this PR:

dub run digger -- build "master + druntime#3160"

@WalterBright
Copy link
Member

I'm seeing the same buildcite/druntime ldc-developers/ldc failure in other PRs. What broke it?

@maxhaton
Copy link
Member Author

@WalterBright as far as I can see it's a style issue in the comments from the C header. I'll push something to fix it soon - if I can't fix it easily I'll just strip them given that the ddoc for the sys.linux packages isn't generated anyway as far as I can see.

@maxhaton
Copy link
Member Author

I removed the comments, passes the checks on my machine now.

Copy link
Member

@Geod24 Geod24 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a lot of weird things here, and it doesn't seem so in line with how other C bindings are handled.

*
* Converted/Bodged from linux userspace header
*
* Copyright: Max Haughton 2020
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better if the copyright was assigned to the foundation instead of yourself.

/*
* D header file for perf_event_open system call.
*
* Converted/Bodged from linux userspace header
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having "bodged" in official documentation doesn't really inspire confidence.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ha. I'll get rid of that tomorrow. Although the docs aren't generated for this folder if I'm not mistaken.

* Converted/Bodged from linux userspace header
*
* Copyright: Max Haughton 2020
* License: <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No HTML please, use macros

else version (ARM64)
{
enum __NR_perf_event_open = 241;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

else
    static assert(0, "Platform not supported");

{
enum __NR_perf_event_open = 241;
}
extern (C) extern long syscall(long __sysno, ...);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm pretty sure we have a binding for this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is not. There are a few PRs but none of them made it in #2820

Comment on lines 277 to 282
private ulong _disabled_inherit_pinned_exclusive_exclude_user_exclude_kernel_exclude_hv_exclude_idle_mmap_comm_freq_inherit_stat_enable_on_exec_task_watermark_precise_ip_mmap_data_sample_id_all_exclude_host_exclude_guest_exclude_callchain_kernel_exclude_callchain_user_mmap2_comm_exec_use_clockid_context_switch_write_backward_namespaces___reserved_1;
@property ulong disabled() @safe pure nothrow @nogc const
{
auto result = (_disabled_inherit_pinned_exclusive_exclude_user_exclude_kernel_exclude_hv_exclude_idle_mmap_comm_freq_inherit_stat_enable_on_exec_task_watermark_precise_ip_mmap_data_sample_id_all_exclude_host_exclude_guest_exclude_callchain_kernel_exclude_callchain_user_mmap2_comm_exec_use_clockid_context_switch_write_backward_namespaces___reserved_1 & 1U) >> 0U;
return cast(ulong) result;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What ?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a mixin from the Phobos bitmanip template. It's not a public interface so I didn't bother renaming it.


struct perf_event_attr
{

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Extra whitespace


enum ulong mispred_min = cast(ulong) 0U;
enum ulong mispred_max = cast(ulong) 1U;
@property ulong predicted() @safe pure nothrow @nogc const
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the whole thing is already nothrow @nogc you don't need those

@Geod24
Copy link
Member

Geod24 commented Jul 15, 2020

Removing the comment is not really a solution IMO, they add a lot of value. What was the failure ?

@maxhaton
Copy link
Member Author

@Geod24 it was a whitespace check in the CI. The comments removal was easier than manually going through several hundred lines of comments - the ABI of perf_event is completely stable at this point so the documentation is in the manpages/online.

@wilzbach
Copy link
Contributor

I'm sorry, but how is removing trailing whitespace going to take more than ten seconds?

@atilaneves
Copy link
Contributor

@Geod24 it was a whitespace check in the CI. The comments removal was easier than manually going through several hundred lines of comments - the ABI of perf_event is completely stable at this point so the documentation is in the manpages/online.

Open in Emacs, M-x delete-trailing-whitespace, done.


ulong sample_type;
ulong read_format;
private ulong _disabled_inherit_pinned_exclusive_exclude_user_exclude_kernel_exclude_hv_exclude_idle_mmap_comm_freq_inherit_stat_enable_on_exec_task_watermark_precise_ip_mmap_data_sample_id_all_exclude_host_exclude_guest_exclude_callchain_kernel_exclude_callchain_user_mmap2_comm_exec_use_clockid_context_switch_write_backward_namespaces___reserved_1;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seriously ? It is private so the mangling does not matter. Reduce the size of this identifier, please.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

eventually you can keep the long stuff in a comment, as it is certainly a very very self documenting name.

@maxhaton
Copy link
Member Author

Fixed it. It wasn't trailing whitespace, it was tabs vs spaces but somehow only in the comments. I was under the impression that it was all spaces, but apparently not - it is now.

@maxhaton
Copy link
Member Author

@Geod24 everything passes now, feedback is incorporated, anything else?

@n8sh
Copy link
Member

n8sh commented Jul 16, 2020

Except for in the definition of perf_callchain_context it looks like every cast(ulong) is unnecessary.

Copy link
Contributor

@RazvanN7 RazvanN7 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@maxhaton Please rebase and let's get this in.

@maxhaton
Copy link
Member Author

@maxhaton Please rebase and let's get this in.

@RazvanN7 Blast from the past, but will do

@Geod24
Copy link
Member

Geod24 commented Aug 25, 2021

Damn I thought this was merged a while ago.

@dlang-bot dlang-bot removed the stalled label Aug 25, 2021
@RazvanN7
Copy link
Contributor

@maxhaton Ping me when it's ready.

maxhaton and others added 6 commits August 26, 2021 19:24
…_event_open is not bound by glibc so I have included a helper

to call this through syscall (in linux unistd) which is in glibc. The bitfields were done via the phobos library (manual mixin inclusion)
…d), the comments are now back with working indentation
Version specifier was incorrect for 64 bit arm

Co-authored-by: Nathan Sashihara <21227491+n8sh@users.noreply.github.com>
@maxhaton maxhaton force-pushed the performance_perf_event branch from c6eafa6 to e7fccbf Compare August 26, 2021 21:58
@maxhaton
Copy link
Member Author

@RazvanN7 Rebased and did a once over documenting everything I could spot. This API should be pretty stable, but I would like to get a test or two in another PR at some point. I have some eBPF bindings somewhere as well, they could go in.

@RazvanN7 RazvanN7 merged commit e6caaab into dlang:master Aug 27, 2021
@RazvanN7
Copy link
Contributor

Thanks, @maxhaton !

Comment on lines +17 to +36
version (X86_64)
{
enum __NR_perf_event_open = 298;
}
else version (X86)
{
enum __NR_perf_event_open = 336;
}
else version (ARM)
{
enum __NR_perf_event_open = 364;
}
else version (AArch64)
{
enum __NR_perf_event_open = 241;
}
else
{
static assert(0, "Architecture not supported");
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should really be rejecting PRs that don't cover all primary supported linux platforms. It's annoying to be running through some finishing line bootstrap tests, and I can't even build druntime anymore on PPC.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well that's why we need to extend the CI here to include you.

// ulong, "__reserved_1", 35));
private ulong perf_event_attr_bitmanip;
///
@property ulong disabled() @safe pure nothrow @nogc const
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's functions here and no unittests? How can we vet that this actually works?

@maxhaton
Copy link
Member Author

maxhaton commented Oct 1, 2021 via email

@maxhaton
Copy link
Member Author

maxhaton commented Oct 1, 2021 via email

@ibuclaw
Copy link
Member

ibuclaw commented Oct 1, 2021

I completely forgot I did that, my bad, do we have syscall tables I can rely upon at build time?

In the version (X86_64) path, D_X32 (-mx32) adds the magic number 0x40000000 to 298.

For all others (HPPA, MIPS, PPC, RISCV, S390, SPARC), you can grab them from musl or glibc sources.


struct
{
import std.bitmanip : bitfields;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$#^*% !!! ???

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants