1*49cdfc7eSAndroid Build Coastguard Worker /*
2*49cdfc7eSAndroid Build Coastguard Worker * Copyright (c) International Business Machines Corp., 2002
3*49cdfc7eSAndroid Build Coastguard Worker * Copyright (C) 2014 Linux Test Project, Inc.
4*49cdfc7eSAndroid Build Coastguard Worker *
5*49cdfc7eSAndroid Build Coastguard Worker * This program is free software; you can redistribute it and/or modify
6*49cdfc7eSAndroid Build Coastguard Worker * it under the terms of the GNU General Public License as published by
7*49cdfc7eSAndroid Build Coastguard Worker * the Free Software Foundation; either version 2 of the License, or
8*49cdfc7eSAndroid Build Coastguard Worker * (at your option) any later version.
9*49cdfc7eSAndroid Build Coastguard Worker *
10*49cdfc7eSAndroid Build Coastguard Worker * This program is distributed in the hope that it will be useful,
11*49cdfc7eSAndroid Build Coastguard Worker * but WITHOUT ANY WARRANTY; without even the implied warranty of
12*49cdfc7eSAndroid Build Coastguard Worker * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See
13*49cdfc7eSAndroid Build Coastguard Worker * the GNU General Public License for more details.
14*49cdfc7eSAndroid Build Coastguard Worker */
15*49cdfc7eSAndroid Build Coastguard Worker /*
16*49cdfc7eSAndroid Build Coastguard Worker * ALGORITHM
17*49cdfc7eSAndroid Build Coastguard Worker * Set up a profiling buffer, turn profiling on, set a timer for
18*49cdfc7eSAndroid Build Coastguard Worker * cpu time, spin the pc and wait for timer to go off.
19*49cdfc7eSAndroid Build Coastguard Worker * The profiling buffer should contain some info, highly concentrated.
20*49cdfc7eSAndroid Build Coastguard Worker * We just do a "looks reasonable" check.
21*49cdfc7eSAndroid Build Coastguard Worker */
22*49cdfc7eSAndroid Build Coastguard Worker
23*49cdfc7eSAndroid Build Coastguard Worker #include <stdio.h>
24*49cdfc7eSAndroid Build Coastguard Worker #include <signal.h>
25*49cdfc7eSAndroid Build Coastguard Worker #include <unistd.h>
26*49cdfc7eSAndroid Build Coastguard Worker #include <errno.h>
27*49cdfc7eSAndroid Build Coastguard Worker #include <sys/types.h>
28*49cdfc7eSAndroid Build Coastguard Worker #include "test.h"
29*49cdfc7eSAndroid Build Coastguard Worker #include "safe_macros.h"
30*49cdfc7eSAndroid Build Coastguard Worker #include "lapi/abisize.h"
31*49cdfc7eSAndroid Build Coastguard Worker #include "config.h"
32*49cdfc7eSAndroid Build Coastguard Worker
33*49cdfc7eSAndroid Build Coastguard Worker char *TCID = "profil01";
34*49cdfc7eSAndroid Build Coastguard Worker
35*49cdfc7eSAndroid Build Coastguard Worker #if HAVE_PROFIL
36*49cdfc7eSAndroid Build Coastguard Worker
37*49cdfc7eSAndroid Build Coastguard Worker #define PROFIL_TIME 5
38*49cdfc7eSAndroid Build Coastguard Worker
39*49cdfc7eSAndroid Build Coastguard Worker /* Should be large enough to hold data for test_profil() .text,
40*49cdfc7eSAndroid Build Coastguard Worker * on x86_64 this is ~600 bytes, so 16k should enough for all arches.
41*49cdfc7eSAndroid Build Coastguard Worker * We will monitor 16k on each side around current pc value,
42*49cdfc7eSAndroid Build Coastguard Worker * just in case compiler put call to get_pc() below "data shuffling" code */
43*49cdfc7eSAndroid Build Coastguard Worker #define PROFIL_BUFLEN (32*1024)
44*49cdfc7eSAndroid Build Coastguard Worker
45*49cdfc7eSAndroid Build Coastguard Worker int TST_TOTAL = 1;
46*49cdfc7eSAndroid Build Coastguard Worker
47*49cdfc7eSAndroid Build Coastguard Worker static volatile sig_atomic_t profil_done;
48*49cdfc7eSAndroid Build Coastguard Worker
alrm_handler(int sig)49*49cdfc7eSAndroid Build Coastguard Worker static void alrm_handler(int sig)
50*49cdfc7eSAndroid Build Coastguard Worker {
51*49cdfc7eSAndroid Build Coastguard Worker (void) sig;
52*49cdfc7eSAndroid Build Coastguard Worker profil_done = 1;
53*49cdfc7eSAndroid Build Coastguard Worker }
54*49cdfc7eSAndroid Build Coastguard Worker
get_pc(void)55*49cdfc7eSAndroid Build Coastguard Worker static void __attribute__ ((noinline)) *get_pc(void)
56*49cdfc7eSAndroid Build Coastguard Worker {
57*49cdfc7eSAndroid Build Coastguard Worker #if defined(__s390__) && defined(TST_ABI32)
58*49cdfc7eSAndroid Build Coastguard Worker /* taken from glibc,
59*49cdfc7eSAndroid Build Coastguard Worker * sysdeps/unix/sysv/linux/s390/s390-32/profil-counter.h
60*49cdfc7eSAndroid Build Coastguard Worker * 31-bit s390 pointers don't use the 32th bit, however integers do,
61*49cdfc7eSAndroid Build Coastguard Worker * so wrap the value around at 31 bits */
62*49cdfc7eSAndroid Build Coastguard Worker return (void *)
63*49cdfc7eSAndroid Build Coastguard Worker ((unsigned long) __builtin_return_address(0) & 0x7fffffffUL);
64*49cdfc7eSAndroid Build Coastguard Worker #else
65*49cdfc7eSAndroid Build Coastguard Worker return __builtin_return_address(0);
66*49cdfc7eSAndroid Build Coastguard Worker #endif
67*49cdfc7eSAndroid Build Coastguard Worker }
68*49cdfc7eSAndroid Build Coastguard Worker
test_profil(void)69*49cdfc7eSAndroid Build Coastguard Worker static void test_profil(void)
70*49cdfc7eSAndroid Build Coastguard Worker {
71*49cdfc7eSAndroid Build Coastguard Worker unsigned short buf[PROFIL_BUFLEN] = { 0 };
72*49cdfc7eSAndroid Build Coastguard Worker volatile int data[8] = { 0 };
73*49cdfc7eSAndroid Build Coastguard Worker size_t offset = (size_t) get_pc() - PROFIL_BUFLEN/2, count = 0;
74*49cdfc7eSAndroid Build Coastguard Worker int ret, i;
75*49cdfc7eSAndroid Build Coastguard Worker
76*49cdfc7eSAndroid Build Coastguard Worker /* reset for test looping */
77*49cdfc7eSAndroid Build Coastguard Worker profil_done = 0;
78*49cdfc7eSAndroid Build Coastguard Worker
79*49cdfc7eSAndroid Build Coastguard Worker /* profil_count in glibc calculates offset as
80*49cdfc7eSAndroid Build Coastguard Worker * i = (pc - pc_offset - (void *) 0) / 2
81*49cdfc7eSAndroid Build Coastguard Worker * i = i * pc_scale / 65536
82*49cdfc7eSAndroid Build Coastguard Worker * set scale to 2*65536 to have 1:1 mapping for $pc */
83*49cdfc7eSAndroid Build Coastguard Worker ret = profil(buf, sizeof(buf), offset, 2*65536);
84*49cdfc7eSAndroid Build Coastguard Worker if (ret)
85*49cdfc7eSAndroid Build Coastguard Worker tst_brkm(TBROK, NULL, "profil returned: %d", ret);
86*49cdfc7eSAndroid Build Coastguard Worker
87*49cdfc7eSAndroid Build Coastguard Worker signal(SIGALRM, alrm_handler);
88*49cdfc7eSAndroid Build Coastguard Worker alarm(PROFIL_TIME);
89*49cdfc7eSAndroid Build Coastguard Worker
90*49cdfc7eSAndroid Build Coastguard Worker while (!profil_done) {
91*49cdfc7eSAndroid Build Coastguard Worker if (data[0])
92*49cdfc7eSAndroid Build Coastguard Worker data[0] = -data[7];
93*49cdfc7eSAndroid Build Coastguard Worker else
94*49cdfc7eSAndroid Build Coastguard Worker data[1] = data[0] / 2;
95*49cdfc7eSAndroid Build Coastguard Worker if (data[2])
96*49cdfc7eSAndroid Build Coastguard Worker data[2] = data[1] * 2;
97*49cdfc7eSAndroid Build Coastguard Worker else
98*49cdfc7eSAndroid Build Coastguard Worker data[3] = data[2] + data[0];
99*49cdfc7eSAndroid Build Coastguard Worker if (data[4])
100*49cdfc7eSAndroid Build Coastguard Worker data[4] = data[3] - data[1];
101*49cdfc7eSAndroid Build Coastguard Worker else
102*49cdfc7eSAndroid Build Coastguard Worker data[5] = data[4] * data[2];
103*49cdfc7eSAndroid Build Coastguard Worker if (data[6])
104*49cdfc7eSAndroid Build Coastguard Worker data[6] = data[5] + data[3];
105*49cdfc7eSAndroid Build Coastguard Worker else
106*49cdfc7eSAndroid Build Coastguard Worker data[7] = data[6] - data[4];
107*49cdfc7eSAndroid Build Coastguard Worker }
108*49cdfc7eSAndroid Build Coastguard Worker
109*49cdfc7eSAndroid Build Coastguard Worker for (i = 0; i < PROFIL_BUFLEN; i++)
110*49cdfc7eSAndroid Build Coastguard Worker if (buf[i]) {
111*49cdfc7eSAndroid Build Coastguard Worker tst_resm(TINFO, "buf[0x%04x]=%d", i, buf[i]);
112*49cdfc7eSAndroid Build Coastguard Worker count += buf[i];
113*49cdfc7eSAndroid Build Coastguard Worker }
114*49cdfc7eSAndroid Build Coastguard Worker
115*49cdfc7eSAndroid Build Coastguard Worker if (count > 0)
116*49cdfc7eSAndroid Build Coastguard Worker tst_resm(TPASS, "profil recorded some data");
117*49cdfc7eSAndroid Build Coastguard Worker else
118*49cdfc7eSAndroid Build Coastguard Worker tst_resm(TFAIL, "profil failed to record anything");
119*49cdfc7eSAndroid Build Coastguard Worker }
120*49cdfc7eSAndroid Build Coastguard Worker
main(int ac,char * av[])121*49cdfc7eSAndroid Build Coastguard Worker int main(int ac, char *av[])
122*49cdfc7eSAndroid Build Coastguard Worker {
123*49cdfc7eSAndroid Build Coastguard Worker int lc;
124*49cdfc7eSAndroid Build Coastguard Worker
125*49cdfc7eSAndroid Build Coastguard Worker tst_parse_opts(ac, av, NULL, NULL);
126*49cdfc7eSAndroid Build Coastguard Worker
127*49cdfc7eSAndroid Build Coastguard Worker for (lc = 0; TEST_LOOPING(lc); lc++)
128*49cdfc7eSAndroid Build Coastguard Worker test_profil();
129*49cdfc7eSAndroid Build Coastguard Worker
130*49cdfc7eSAndroid Build Coastguard Worker tst_exit();
131*49cdfc7eSAndroid Build Coastguard Worker }
132*49cdfc7eSAndroid Build Coastguard Worker #else /* systems without profil() */
main(void)133*49cdfc7eSAndroid Build Coastguard Worker int main(void)
134*49cdfc7eSAndroid Build Coastguard Worker {
135*49cdfc7eSAndroid Build Coastguard Worker tst_brkm(TCONF, NULL, "system doesn't have profil() support");
136*49cdfc7eSAndroid Build Coastguard Worker }
137*49cdfc7eSAndroid Build Coastguard Worker #endif
138