/****************************/
/* THIS IS OPEN SOURCE CODE */
/****************************/
/**
* @file: PAPI_Matlab.c
* CVS: $Id$
* @author Joseph Thomas <jthomas@cs.utk.edu>
*
* @brief PAPI Matlab integration.
* See PAPI_Matlab.readme for more information.
*/
#include "mex.h"
#include "matrix.h"
#include "papi.h"
static long long accum_error = 0;
static long long start_time = 0;
void mexFunction(int nlhs, mxArray *plhs[],
int nrhs, const mxArray *prhs[]) {
float real_time, proc_time, rate;
int i;
int number_of_counters;
unsigned int mrows, nchars;
unsigned int *events;
unsigned int flop_events[2];
long long ins = 0, *values, flop_values[2];
long long elapsed_time;
int result;
char *input, *temp;
char one_output[] = "This function produces one output per running counter.";
char no_input[] = "This function expects no input.";
char error_reading[] = "Error reading the running counters.";
/* Check for proper number of arguments. */
if(nrhs < 1) {
mexErrMsgTxt("This function expects input.");
}
nchars = mxGetNumberOfElements(prhs[0]);
input = (char *)mxCalloc(nchars, sizeof(char) + 1);
input = mxArrayToString(prhs[0]);
if(!strncmp(input, "num", 3)) {
if(nrhs != 1) {
mexErrMsgTxt(no_input);
}
else if(nlhs != 1) {
mexErrMsgTxt("This function produces one and only one output: counters.");
}
result = PAPI_num_counters();
if(result < PAPI_OK) {
mexPrintf("Error code: %d\n", result);
mexErrMsgTxt("Error reading counters.");
}
plhs[0] = mxCreateDoubleScalar((double)result);
}
else if((!strncmp(input, "flip", 4)) || (!strncmp(input, "flop", 4))) {
if(nrhs != 1) {
mexErrMsgTxt(no_input);
} else if(nlhs > 2) {
if (input[2] == 'i')
mexErrMsgTxt("This function produces 1 or 2 outputs: [ops, mflips].");
else
mexErrMsgTxt("This function produces 1 or 2 outputs: [ops, mflops].");
}
if (input[2] == 'i') {
if(result = PAPI_flips( &real_time, &proc_time, &ins, &rate)<PAPI_OK) {
mexPrintf("Error code: %d\n", result);
mexErrMsgTxt("Error getting flips.");
}
} else {
if(result = PAPI_event_name_to_code("EMON_SSE_SSE2_COMP_INST_RETIRED_PACKED_DOUBLE", &(flop_events[0])) < PAPI_OK) {
if(result = PAPI_flops( &real_time, &proc_time, &ins, &rate)<PAPI_OK) {
mexPrintf("Error code: %d\n", result);
mexErrMsgTxt("Error getting flops.");
}
} else {
if(start_time == 0) {
flop_events[1] = PAPI_FP_OPS;
start_time = PAPI_get_real_usec();
if((result = PAPI_start_counters(flop_events, 2)) < PAPI_OK) {
mexPrintf("Error code: %d\n", result);
mexErrMsgTxt("Error getting flops.");
} else {
ins = 0;
rate = 0;
}
} else {
if((result = PAPI_read_counters(flop_values, 2)) < PAPI_OK) {
mexPrintf("%d\n", result);
mexErrMsgTxt(error_reading);
} else {
elapsed_time = PAPI_get_real_usec() - start_time;
ins = (2*flop_values[0])+flop_values[1];
rate = ((float)ins)/((float)elapsed_time);
}
}
}
}
if(nlhs > 0) {
plhs[0] = mxCreateDoubleScalar((double)(ins - accum_error));
/* this call adds 7 fp instructions to the total */
/* but apparently not on Pentium M with Matlab 7.0.4 */
/* accum_error += 7; */
if(nlhs == 2) {
plhs[1] = mxCreateDoubleScalar((double)rate);
/* the second call adds 4 fp instructions to the total */
/* but apparently not on Pentium M with Matlab 7.0.4 */
/* accum_error += 4; */
}
}
}
else if(!strncmp(input, "start", 5)) {
if(nlhs != 0) {
mexErrMsgTxt("This function produces no output.");
}
if(nrhs > (PAPI_num_counters() + 1)) {
mexErrMsgTxt(one_output);
}
mrows = mxGetM(prhs[1]);
events = (unsigned int *)mxCalloc(nrhs - 1, sizeof(int) + 1);
for(i = 1; i < nrhs; i++) {
if(mxIsComplex(prhs[i]) || !(mrows == 1) ) {
mexErrMsgTxt("Input must be a list of strings.");
}
if(mxIsChar(prhs[i])) {
nchars = mxGetNumberOfElements(prhs[i]);
temp = (char *)mxCalloc(nchars, sizeof(char) + 1);
temp = mxArrayToString(prhs[i]);
if(result = PAPI_event_name_to_code(temp, &(events[i - 1])) < PAPI_OK) {
mxFree(temp);
mexPrintf("Error code: %d\n", result);
mexErrMsgTxt("Incorrect PAPI code given.");
}
mxFree(temp);
}
else {
events[i - 1] = (unsigned int)mxGetScalar(prhs[i]);
}
}
if((result = PAPI_start_counters(events, nrhs - 1)) < PAPI_OK) {
mxFree(events);
mexPrintf("Error code: %d\n", result);
mexErrMsgTxt("Error initializing counters.");
}
mxFree(events);
}
else if(!strncmp(input, "stop", 4)) {
if(nrhs != 1) {
mexErrMsgTxt(no_input);
}
number_of_counters = PAPI_num_counters();
if(nlhs > number_of_counters ) {
mexErrMsgTxt(one_output);
}
if (nlhs == 0)
values = (long long*)mxCalloc(number_of_counters, sizeof(long long));
else
values = (long long *)mxCalloc(nlhs, sizeof(long long) + 1);
if (start_time == 0) {
if (nlhs == 0)
result = PAPI_stop_counters(values, number_of_counters);
else
result = PAPI_stop_counters(values, nlhs);
} else {
start_time = 0;
result = PAPI_stop_counters(flop_values, 2);
}
if(result < PAPI_OK) {
if(result != PAPI_ENOTRUN) {
mexPrintf("Error code: %d\n", result);
mexErrMsgTxt("Error stopping the running counters.");
}
}
accum_error = 0;
for(i = 0; i < nlhs; i++) {
plhs[i] = mxCreateDoubleScalar((double)values[i]);
}
mxFree(values);
}
else if(!strncmp(input, "read", 4)) {
if(nrhs != 1) {
mexErrMsgTxt(no_input);
}
if(nlhs > PAPI_num_counters()) {
mexErrMsgTxt(one_output);
}
values = (long long *)mxCalloc(nlhs, sizeof(long long) + 1);
if((result = PAPI_read_counters(values, nlhs)) < PAPI_OK) {
mexPrintf("%d\n", result);
mexErrMsgTxt(error_reading);
}
for(i = 0; i < nlhs; i++) {
plhs[i] = mxCreateDoubleScalar((double)values[i]);
}
mxFree(values);
}
else if(!strncmp(input, "accum", 5)) {
if(nrhs > PAPI_num_counters() + 1) {
mexErrMsgTxt(no_input);
}
if(nlhs > PAPI_num_counters()) {
mexErrMsgTxt(one_output);
}
values = (long long *)mxCalloc(nlhs, sizeof(long long) + 1);
for(i = 0; i < nrhs - 1; i++) {
values[i] = (long long)(*(mxGetPr(prhs[i + 1])));
}
if(result = PAPI_accum_counters(values, nlhs) < PAPI_OK) {
mexPrintf("Error code: %d\n", result);
mexErrMsgTxt(error_reading);
}
for(i = 0; i < nlhs; i++) {
plhs[i] = mxCreateDoubleScalar((double)values[i]);
}
mxFree(values);
}
else if(!strncmp(input, "ipc", 3)) {
if(nrhs != 1) {
mexErrMsgTxt(no_input);
} else if(nlhs > 2) {
mexErrMsgTxt("This function produces 1 or 2 outputs: [ops, ipc].");
}
if(PAPI_ipc(&real_time, &proc_time, &ins, &rate)<PAPI_OK) {
mexErrMsgTxt("Error getting instruction rate.");
}
if(nlhs > 0) {
plhs[0] = mxCreateDoubleScalar((double)ins);
if(nlhs == 2) {
plhs[1] = mxCreateDoubleScalar((double)rate);
}
}
}
else {
mexPrintf("Cannot find the command you specified.\n");
mexErrMsgTxt("See the included readme file.");
}
}