138 lines
3.4 KiB
C
138 lines
3.4 KiB
C
/*
|
|
* 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"
|
|
#include "lapi/abisize.h"
|
|
#include "config.h"
|
|
|
|
char *TCID = "profil01";
|
|
|
|
#if HAVE_PROFIL
|
|
|
|
#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)
|
|
|
|
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)
|
|
{
|
|
#if defined(__s390__) && defined(TST_ABI32)
|
|
/* taken from glibc,
|
|
* sysdeps/unix/sysv/linux/s390/s390-32/profil-counter.h
|
|
* 31-bit s390 pointers don't use the 32th bit, however integers do,
|
|
* so wrap the value around at 31 bits */
|
|
return (void *)
|
|
((unsigned long) __builtin_return_address(0) & 0x7fffffffUL);
|
|
#else
|
|
return __builtin_return_address(0);
|
|
#endif
|
|
}
|
|
|
|
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", 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;
|
|
|
|
tst_parse_opts(ac, av, NULL, NULL);
|
|
|
|
for (lc = 0; TEST_LOOPING(lc); lc++)
|
|
test_profil();
|
|
|
|
tst_exit();
|
|
}
|
|
#else /* systems without profil() */
|
|
int main(void)
|
|
{
|
|
tst_brkm(TCONF, NULL, "system doesn't have profil() support");
|
|
}
|
|
#endif
|