| /* |
| * Copyright (c) International Business Machines Corp., 2002 |
| * Copyright (C) 2014 Linux Test Project, Inc. |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 2 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See |
| * the GNU General Public License for more details. |
| */ |
| /* |
| * ALGORITHM |
| * Set up a profiling buffer, turn profiling on, set a timer for |
| * cpu time, spin the pc and wait for timer to go off. |
| * The profiling buffer should contain some info, highly concentrated. |
| * We just do a "looks reasonable" check. |
| */ |
| |
| #include <stdio.h> |
| #include <signal.h> |
| #include <unistd.h> |
| #include <errno.h> |
| #include <sys/types.h> |
| #include "test.h" |
| #include "safe_macros.h" |
| |
| #define PROFIL_TIME 5 |
| |
| /* Should be large enough to hold data for test_profil() .text, |
| * on x86_64 this is ~600 bytes, so 16k should enough for all arches. |
| * We will monitor 16k on each side around current pc value, |
| * just in case compiler put call to get_pc() below "data shuffling" code */ |
| #define PROFIL_BUFLEN (32*1024) |
| |
| char *TCID = "profil01"; |
| int TST_TOTAL = 1; |
| |
| static volatile sig_atomic_t profil_done; |
| |
| static void alrm_handler(int sig) |
| { |
| (void) sig; |
| profil_done = 1; |
| } |
| |
| static void __attribute__ ((noinline)) *get_pc(void) |
| { |
| return __builtin_return_address(0); |
| } |
| |
| static void test_profil(void) |
| { |
| unsigned short buf[PROFIL_BUFLEN] = { 0 }; |
| volatile int data[8] = { 0 }; |
| size_t offset = (size_t) get_pc() - PROFIL_BUFLEN/2, count = 0; |
| int ret, i; |
| |
| /* reset for test looping */ |
| profil_done = 0; |
| |
| /* profil_count in glibc calculates offset as |
| * i = (pc - pc_offset - (void *) 0) / 2 |
| * i = i * pc_scale / 65536 |
| * set scale to 2*65536 to have 1:1 mapping for $pc */ |
| ret = profil(buf, sizeof(buf), offset, 2*65536); |
| if (ret) |
| tst_brkm(TBROK, NULL, "profil returned: %d\n", ret); |
| |
| signal(SIGALRM, alrm_handler); |
| alarm(PROFIL_TIME); |
| |
| while (!profil_done) { |
| if (data[0]) |
| data[0] = -data[7]; |
| else |
| data[1] = data[0] / 2; |
| if (data[2]) |
| data[2] = data[1] * 2; |
| else |
| data[3] = data[2] + data[0]; |
| if (data[4]) |
| data[4] = data[3] - data[1]; |
| else |
| data[5] = data[4] * data[2]; |
| if (data[6]) |
| data[6] = data[5] + data[3]; |
| else |
| data[7] = data[6] - data[4]; |
| } |
| |
| for (i = 0; i < PROFIL_BUFLEN; i++) |
| if (buf[i]) { |
| tst_resm(TINFO, "buf[0x%04x]=%d", i, buf[i]); |
| count += buf[i]; |
| } |
| |
| if (count > 0) |
| tst_resm(TPASS, "profil recorded some data"); |
| else |
| tst_resm(TFAIL, "profil failed to record anything"); |
| } |
| |
| int main(int ac, char *av[]) |
| { |
| int lc; |
| const char *msg; |
| |
| msg = parse_opts(ac, av, NULL, NULL); |
| if (msg != NULL) |
| tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg); |
| |
| for (lc = 0; TEST_LOOPING(lc); lc++) |
| test_profil(); |
| |
| tst_exit(); |
| } |