You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
183 lines
4.7 KiB
183 lines
4.7 KiB
/*
|
|
* Copyright 2002-2019 Intel Corporation.
|
|
*
|
|
* This software is provided to you as Sample Source Code as defined in the accompanying
|
|
* End User License Agreement for the Intel(R) Software Development Products ("Agreement")
|
|
* section 1.L.
|
|
*
|
|
* This software and the related documents are provided as is, with no express or implied
|
|
* warranties, other than those that are expressly stated in the License.
|
|
*/
|
|
|
|
/*
|
|
* This application is used with several tests. It executes the global function
|
|
* InstrumentedWithPin() in parallel with several threads. Pin tools can add
|
|
* instrumentation to that function to test parallel calls to an analysis routine.
|
|
*
|
|
* This application uses Posix API's, but there is a similar implementation
|
|
* that works on Windows platforms.
|
|
*/
|
|
|
|
#include <iostream>
|
|
#include <cstdlib>
|
|
#include <cstring>
|
|
#include <climits>
|
|
#include <pthread.h>
|
|
#include <unistd.h>
|
|
#include <limits.h>
|
|
#include "atomic.hpp"
|
|
|
|
#if defined(FUND_HOST_MAC)
|
|
# include <sys/types.h>
|
|
# include <sys/sysctl.h>
|
|
#endif
|
|
|
|
|
|
extern "C" void InstrumentedWithPin(volatile UINT32 *);
|
|
extern "C" void TellPinThreadCount(ADDRINT);
|
|
extern "C" void TellPinThreadStart();
|
|
|
|
static unsigned const DEFAULT_CPU_COUNT = 2;
|
|
|
|
typedef void (*FUNPTR1)(volatile UINT32 *);
|
|
typedef void (*FUNPTR2)(ADDRINT);
|
|
typedef void (*FUNPTR3)();
|
|
|
|
static volatile bool Ready = false;
|
|
|
|
static unsigned GetThreadCount(int, char **);
|
|
static unsigned GetCpuCount();
|
|
static void *Worker(void *);
|
|
|
|
|
|
int main(int argc, char **argv)
|
|
{
|
|
unsigned numThreads = GetThreadCount(argc, argv);
|
|
if (!numThreads)
|
|
return 1;
|
|
|
|
std::cout << "Testing with threads: " << std::dec << numThreads << std::endl;
|
|
|
|
// Tell the Pin tool the number of worker threads.
|
|
//
|
|
volatile FUNPTR2 tellPinCount = TellPinThreadCount;
|
|
tellPinCount(numThreads);
|
|
|
|
pthread_t *thds = new pthread_t[numThreads];
|
|
for (unsigned i = 0; i < numThreads; i++)
|
|
{
|
|
if (pthread_create(&thds[i], 0, Worker, 0) != 0)
|
|
{
|
|
std::cerr << "Unable to create worker thread #" << std::dec << i << std::endl;
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
// Tell all the worker threads to go.
|
|
//
|
|
ATOMIC::OPS::Store(&Ready, true);
|
|
|
|
for (unsigned i = 0; i < numThreads; i++)
|
|
pthread_join(thds[i], 0);
|
|
delete [] thds;
|
|
return 0;
|
|
}
|
|
|
|
static unsigned GetThreadCount(int argc, char **argv)
|
|
{
|
|
// If there's no explicit thread parameter, use the number of CPU's
|
|
// but not less than 2 and not more than 8.
|
|
//
|
|
if (argc <= 1)
|
|
{
|
|
unsigned ncpus = GetCpuCount();
|
|
if (ncpus < 2)
|
|
ncpus = 2;
|
|
if (ncpus > 8)
|
|
ncpus = 8;
|
|
return ncpus;
|
|
}
|
|
|
|
if (std::strcmp(argv[1], "-t") != 0)
|
|
{
|
|
std::cerr << "Unknown option: " << argv[1] << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
if (argc < 3)
|
|
{
|
|
std::cerr << "Must specify a parameter to '-t'" << std::endl;
|
|
return 0;
|
|
}
|
|
|
|
char *end;
|
|
unsigned long val = std::strtoul(argv[2], &end, 10);
|
|
if (*(argv[2]) == '\0' || val > UINT_MAX || val == 0 || *end != '\0')
|
|
{
|
|
std::cerr << "Invalid parameter to -t: " << argv[2] << std::endl;
|
|
return 0;
|
|
}
|
|
return static_cast<unsigned>(val);
|
|
}
|
|
|
|
static unsigned GetCpuCount()
|
|
{
|
|
#if defined(FUND_HOST_LINUX) || defined(FUND_HOST_BSD)
|
|
|
|
long count = sysconf(_SC_NPROCESSORS_ONLN);
|
|
if (count != -1)
|
|
return count;
|
|
|
|
#elif defined(FUND_HOST_MAC)
|
|
|
|
int mib[2];
|
|
mib[0] = CTL_HW;
|
|
mib[1] = HW_NCPU;
|
|
unsigned ncpu;
|
|
size_t len = sizeof(ncpu);
|
|
if (sysctl(mib, 2, &ncpu, &len, 0, 0) == 0)
|
|
return ncpu;
|
|
|
|
#endif
|
|
|
|
std::cout << "Unable to get system CPU count, using default" << std::endl;
|
|
return DEFAULT_CPU_COUNT;
|
|
}
|
|
|
|
static void *Worker(void *)
|
|
{
|
|
volatile FUNPTR3 threadstarted = TellPinThreadStart;
|
|
threadstarted();
|
|
// Wait for all the worker threads to be created. We use an active
|
|
// spin loop here to help ensure that all thread execute the loop below
|
|
// in parallel.
|
|
//
|
|
while (!ATOMIC::OPS::Load(&Ready));
|
|
|
|
// Call InstrumentedWithPin() through a volatile pointer to prevent the compiler
|
|
// from inlining the body.
|
|
//
|
|
volatile FUNPTR1 doFun = InstrumentedWithPin;
|
|
volatile UINT32 done = 0;
|
|
while (!done)
|
|
doFun(&done);
|
|
|
|
return 0;
|
|
}
|
|
|
|
extern "C" void InstrumentedWithPin(volatile UINT32 *done)
|
|
{
|
|
// Pin tool places instrumentation here.
|
|
// It stores non-zero to 'done' when the thread should exit.
|
|
}
|
|
|
|
extern "C" void TellPinThreadCount(ADDRINT threadCount)
|
|
{
|
|
// Pin tool can place instrumentation here to learn the worker thread count.
|
|
}
|
|
|
|
extern "C" void TellPinThreadStart()
|
|
{
|
|
// Pin tool can place instrumentation here to know the worker thread started.
|
|
}
|