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.

153 lines
4.2 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 Windows API's, but there is a similar implementation
* that works on Unix platforms.
*/
#include <iostream>
#include <windows.h>
#include "atomic.hpp"
extern "C" __declspec(dllexport) void InstrumentedWithPin(volatile UINT32 *);
extern "C" __declspec(dllexport) void TellPinThreadCount(ADDRINT);
extern "C" __declspec(dllexport) void TellPinThreadStart();
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 DWORD WINAPI Worker(LPVOID);
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);
HANDLE *thds = new HANDLE[numThreads];
for (unsigned i = 0; i < numThreads; i++)
{
thds[i] = CreateThread(0, 0, Worker, 0, 0, 0);
if (!thds[i])
{
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++)
WaitForSingleObject(thds[i], INFINITE);
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()
{
SYSTEM_INFO info;
GetSystemInfo(&info);
return static_cast<unsigned>(info.dwNumberOfProcessors);
}
static DWORD WINAPI Worker(LPVOID)
{
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.
}