blob: cdf88158abfff63978a6198f25bf86917b34d2f0 [file] [log] [blame]
/*
*Licensed to the Apache Software Foundation (ASF) under one
*or more contributor license agreements. See the NOTICE file
*distributed with this work for additional information
*regarding copyright ownership. The ASF licenses this file
*to you under the Apache License, Version 2.0 (the
*"License"); you may not use this file except in compliance
*with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*Unless required by applicable law or agreed to in writing,
*software distributed under the License is distributed on an
*"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
*specific language governing permissions and limitations
*under the License.
*/
#include <stdlib.h>
#include <pthread.h>
#include <unistd.h>
#include <sys/time.h>
#include <pthread.h>
#include "array_list.h"
#include "benchmark.h"
#include "math_service.h"
static const char * const BENCHMARK_NAME = "MODIFIED_BIT";
static const double SAMPLE_FACTOR = 1;
static const useconds_t SLEEP_TIME = 10;
typedef struct thread_info {
benchmark_pt benchmark;
unsigned int result;
struct timeval begin;
struct timeval end;
int skips;
bool isModified;
bool isUpdated;
} thread_info_t;
struct benchmark {
pthread_mutex_t mutex;
math_service_pt math;
int nrOfSamples;
int nrOfThreads;
thread_info_t *threads;
};
static void benchmark_thread(thread_info_t *info);
celix_status_t benchmark_create(benchmark_pt *benchmark) {
(*benchmark) = malloc(sizeof(struct benchmark));
(*benchmark)->math = NULL;
pthread_mutex_init(&(*benchmark)->mutex, NULL);
return CELIX_SUCCESS;
}
celix_status_t benchmark_destroy(benchmark_pt benchmark) {
//free threads array
free(benchmark);
return CELIX_SUCCESS;
}
benchmark_result_t benchmark_run(benchmark_pt benchmark, int nrOfThreads, int nrOfSamples) {
int i;
pthread_t threads[nrOfThreads];
thread_info_t infos[nrOfThreads];
benchmark_result_t result;
unsigned long elapsedTime = 0;
benchmark->threads = infos;
benchmark->nrOfSamples = nrOfSamples;
benchmark->nrOfThreads = nrOfThreads;
result.skips =0;
pthread_mutex_lock(&benchmark->mutex);
for (i = 0 ; i < nrOfThreads ; i += 1) {
infos[i].benchmark = benchmark;
infos[i].skips = 0;
infos[i].result = rand();
infos[i].isUpdated = false;
infos[i].isModified = false;
pthread_create(&threads[i], NULL, (void *)benchmark_thread, &infos[i]);
}
pthread_mutex_unlock(&benchmark->mutex);
for (i = 0; i < nrOfThreads ; i += 1) {
pthread_join(threads[i], NULL);
elapsedTime += ((infos[i].end.tv_sec - infos[i].begin.tv_sec) * 1000000) + (infos[i].end.tv_usec - infos[i].begin.tv_usec);
result.skips += infos[i].skips;
}
result.averageCallTimeInNanoseconds = ((double)elapsedTime * 1000) / (nrOfSamples * nrOfThreads);
result.callFrequencyInMhz = ((double)(nrOfSamples * nrOfThreads) / elapsedTime);
result.nrOfThreads = nrOfThreads;
result.nrOfsamples = nrOfSamples;
return result;
}
static void benchmark_thread(thread_info_t *info) {
int i = 0;
math_service_pt local = info->benchmark->math;
int nrOfSamples = info->benchmark->nrOfSamples;
gettimeofday(&info->begin, NULL);
while (i < nrOfSamples) {
if (!info->isModified) {
if (local != NULL) {
info->result = local->calc(local->handle, info->result, i);
} else {
info->skips += 1; //should not happen
}
i += 1;
} else {
local = info->benchmark->math;
info->isModified = false;
}
}
gettimeofday(&info->end, NULL);
}
char * benchmark_getName(benchmark_pt benchmark) {
return (char *)BENCHMARK_NAME;
}
celix_status_t benchmark_addMathService(benchmark_pt benchmark, math_service_pt mathService) {
int i;
pthread_mutex_lock(&benchmark->mutex);
benchmark->math = mathService;
pthread_mutex_unlock(&benchmark->mutex);
//inform threads to update servicd
for (i = 0 ; i < benchmark->nrOfSamples ; i += 1) {
benchmark->threads[i].isModified = true;
}
//Wait till al thread are not in a modified state, e.g. update to date mathService and not using the old service
for (i = 0; i < benchmark->nrOfThreads ; i += 1) {
if (benchmark->threads[i].isModified) {
usleep(SLEEP_TIME);
}
}
return CELIX_SUCCESS;
}
celix_status_t benchmark_removeMathService(benchmark_pt benchmark, math_service_pt mathService) {
pthread_mutex_lock(&benchmark->mutex);
if (benchmark->math == mathService) {
benchmark->math = NULL;
}
pthread_mutex_unlock(&benchmark->mutex);
//inform threads to update servicd
int i;
for (i = 0 ; i < benchmark->nrOfThreads ; i += 1) {
benchmark->threads[i].isModified = true;
}
//Wait till al thread are not in a modified state, e.g. update to date mathService and not using the old service
for (i = 0; i < benchmark->nrOfThreads ; i += 1) {
if (benchmark->threads[i].isModified) {
usleep(SLEEP_TIME);
}
}
return CELIX_SUCCESS;
}
double benchmark_getSampleFactor(benchmark_pt benchmark) {
return SAMPLE_FACTOR;
}