• Michael O'Farrell's avatar
    arm64: perf: Add cap_user_time aarch64 · 9d2dcc8f
    Michael O'Farrell authored
    It is useful to get the running time of a thread.  Doing so in an
    efficient manner can be important for performance of user applications.
    Avoiding system calls in `clock_gettime` when handling
    CLOCK_THREAD_CPUTIME_ID is important.  Other clocks are handled in the
    VDSO, but CLOCK_THREAD_CPUTIME_ID falls back on the system call.
    
    CLOCK_THREAD_CPUTIME_ID is not handled in the VDSO since it would have
    costs associated with maintaining updated user space accessible time
    offsets.  These offsets have to be updated everytime the a thread is
    scheduled/descheduled.  However, for programs regularly checking the
    running time of a thread, this is a performance improvement.
    
    This patch takes a middle ground, and adds support for cap_user_time an
    optional feature of the perf_event API.  This way costs are only
    incurred when the perf_event api is enabled.  This is done the same way
    as it is in x86.
    
    Ultimately this allows calculating the thread running time in userspace
    on aarch64 as follows (adapted from perf_event_open manpage):
    
    u32 seq, time_mult, time_shift;
    u64 running, count, time_offset, quot, rem, delta;
    struct perf_event_mmap_page *pc;
    pc = buf;  // buf is the perf event mmaped page as documented in the API.
    
    if (pc->cap_usr_time) {
        do {
            seq = pc->lock;
            barrier();
            running = pc->time_running;
    
            count = readCNTVCT_EL0();  // Read ARM hardware clock.
            time_offset = pc->time_offset;
            time_mult   = pc->time_mult;
            time_shift  = pc->time_shift;
    
            barrier();
        } while (pc->lock != seq);
    
        quot = (count >> time_shift);
        rem = count & (((u64)1 << time_shift) - 1);
        delta = time_offset + quot * time_mult +
                ((rem * time_mult) >> time_shift);
    
        running += delta;
        // running now has the current nanosecond level thread time.
    }
    
    Summary of changes in the patch:
    
    For aarch64 systems, make arch_perf_update_userpage update the timing
    information stored in the perf_event page.  Requiring the following
    calculations:
      - Calculate the appropriate time_mult, and time_shift factors to convert
        ticks to nano seconds for the current clock frequency.
      - Adjust the mult and shift factors to avoid shift factors of 32 bits.
        (possibly unnecessary)
      - The time_offset userspace should apply when doing calculations:
        negative the current sched time (now), because time_running and
        time_enabled fields of the perf_event page have just been updated.
    Toggle bits to appropriate values:
      - Enable cap_user_time
    Signed-off-by: default avatarMichael O'Farrell <micpof@gmail.com>
    Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
    9d2dcc8f
perf_event.c 40.8 KB