I recently came across a simple problem in C++, but a difficult one in OpenCL: comparing dates. Since I needed this functionality in one of my algorithms, I decided to implement my own OpenCL diffDays function and here is what it looks like the one bellow.
// GlobalsOpenCL
__constant int DaysInMonths[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
// Macros
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)
typedef struct
{
int tm_sec;
int tm_min;
int tm_hour;
int tm_mday;
int tm_mon;
int tm_year;
int tm_wday;
int tm_yday;
int tm_isdst;
} TimeStructure;
void computeYearDay( TimeStructure* t )
{
int nbDays = 0;
for( int i=0; i<(*t).tm_mon-1; ++i )
{
nbDays += DaysInMonths[i];
}
nbDays += (*t).tm_mday;
nbDays += isleap((*t).tm_year ) ? 1 : 0; // leap years
(*t).tm_yday = nbDays;
}
int diffDays(TimeStructure fromDate, TimeStructure toDate)
{
int fndays = 0;
float fndaysFrom = 0.f;
float fndaysTo = 0.f;
int ndays = 0;
computeYearDay(&fromDate);
computeYearDay(&toDate);
int toYear = 1900 + toDate.tm_year;
int fromYear = 1900 + fromDate.tm_year;
fndaysFrom = (float)(fromDate.tm_mday);
fndaysFrom += (float)(fromDate.tm_hour)/24.f;
fndaysFrom += (float)(fromDate.tm_min)/1440.f;
fndaysFrom += (float)(fromDate.tm_sec)/86400.f;
fndaysTo = (float)(toDate.tm_mday);
fndaysTo += (float)(toDate.tm_hour)/24.f;
fndaysTo += (float)(toDate.tm_min)/1440.f;
fndaysTo += (float)(toDate.tm_sec)/86400.f;
for(int i=fromYear; i < toYear; i++) {
ndays += isleap(i) ? 366 : 365;
}
fndays = ndays + (fndaysTo - fndaysFrom);
return -fndays;
}
The funny thing about it that when I tried to compare the results between CPU execution (using OpenMP) and the OpenCL implementation, I realized that my C++ code could not scale properly. Even worse, it was slowing down as I was increasing the number of cores. After a good profiling session using Intel Parallel Studio, I realized that the slowing bit was in the mktime function provided with Microsoft Visual C++ 2010. So I ported the OpenCL function back to C++ and that resulted in an amazing x20 increase in performance on 8 CPUs.
And I now have a mktime that scales on multicore architectures !!
The funny thing about it that when I tried to compare the results between CPU execution (using OpenMP) and the OpenCL implementation, I realized that my C++ code could not scale properly. Even worse, it was slowing down as I was increasing the number of cores. After a good profiling session using Intel Parallel Studio, I realized that the slowing bit was in the mktime function provided with Microsoft Visual C++ 2010. So I ported the OpenCL function back to C++ and that resulted in an amazing x20 increase in performance on 8 CPUs.
And I now have a mktime that scales on multicore architectures !!
C/C++
#define isleap(y) ((((y) % 4) == 0 && ((y) % 100) != 0) || ((y) % 400) == 0)const int DaysInMonths[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
void computeYearDay( tm& t )
{
int nbDays = 0;
for( int i=0; i<t.tm_mon-1; ++i )
{
nbDays += DaysInMonths[i];
}
nbDays += t.tm_mday;
nbDays += isleap(t.tm_year ) ? 1 : 0;
t.tm_yday = nbDays;
}
int diffDays(tm b, tm a)
{
int fndays = 0;
float fndaysFrom = 0.f;
float fndaysTo = 0.f;
int ndays = 0;
computeYearDay(b);
computeYearDay(a);
int toYear = 1900 + a.tm_year;
int fromYear = 1900 + b.tm_year;
fndaysFrom = static_cast<float>(b.tm_mday);
fndaysFrom += static_cast<float>(b.tm_hour)/24.f;
fndaysFrom += static_cast<float>(b.tm_min)/1440.f;
fndaysFrom += static_cast<float>(b.tm_sec)/86400.f;
fndaysTo = static_cast<float>(a.tm_mday);
fndaysTo += static_cast<float>(a.tm_hour)/24.f;
fndaysTo += static_cast<float>(a.tm_min)/1440.f;
fndaysTo += static_cast<float>(a.tm_sec)/86400.f;
for(int i=fromYear; i < toYear; i++) {
ndays += isleap(i) ? 366 : 365;
}
fndays = ndays + (fndaysTo - fndaysFrom);
return -fndays;
}