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