diff --git a/.hgignore b/.hgignore index b6cc9203..8dd55b6d 100644 --- a/.hgignore +++ b/.hgignore @@ -117,3 +117,5 @@ tests/xattr/mimeview website/usermanual/* website/idxthreads/forkingRecoll.html website/idxthreads/xapDocCopyCrash.html +website/pages/recoll-mingw.html +website/pages/recoll-windows.html diff --git a/src/Makefile.am b/src/Makefile.am index 807935c8..482d191e 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -182,6 +182,8 @@ utils/appformime.h \ utils/base64.cpp \ utils/base64.h \ utils/cancelcheck.h \ +utils/chrono.h \ +utils/chrono.cpp \ utils/circache.cpp \ utils/circache.h \ utils/closefrom.cpp \ diff --git a/src/index/fsindexer.cpp b/src/index/fsindexer.cpp index fcb9375b..046335ab 100644 --- a/src/index/fsindexer.cpp +++ b/src/index/fsindexer.cpp @@ -39,6 +39,7 @@ #include "debuglog.h" #include "internfile.h" #include "smallut.h" +#include "chrono.h" #include "wipedir.h" #include "fileudi.h" #include "cancelcheck.h" @@ -239,7 +240,7 @@ bool FsIndexer::index(int flags) } m_config->storeMissingHelperDesc(missing); } - LOGINFO(("fsindexer index time: %d mS\n", chron.ms())); + LOGINFO(("fsindexer index time: %d mS\n", chron.millis())); return true; } diff --git a/src/index/recollindex.cpp b/src/index/recollindex.cpp index e9990f43..50d0befb 100644 --- a/src/index/recollindex.cpp +++ b/src/index/recollindex.cpp @@ -40,6 +40,7 @@ using namespace std; #include "rclinit.h" #include "indexer.h" #include "smallut.h" +#include "chrono.h" #include "pathut.h" #include "rclmon.h" #include "x11mon.h" diff --git a/src/qtgui/preview_w.cpp b/src/qtgui/preview_w.cpp index c49b40d6..7b34ccc8 100644 --- a/src/qtgui/preview_w.cpp +++ b/src/qtgui/preview_w.cpp @@ -51,6 +51,7 @@ #include "recoll.h" #include "plaintorich.h" #include "smallut.h" +#include "chrono.h" #include "wipedir.h" #include "cancelcheck.h" #include "preview_w.h" diff --git a/src/query/plaintorich.cpp b/src/query/plaintorich.cpp index fab02e8d..559c9002 100644 --- a/src/query/plaintorich.cpp +++ b/src/query/plaintorich.cpp @@ -35,6 +35,7 @@ using std::set; #include "textsplit.h" #include "utf8iter.h" #include "smallut.h" +#include "chrono.h" #include "plaintorich.h" #include "cancelcheck.h" #include "unacpp.h" diff --git a/src/query/recollq.cpp b/src/query/recollq.cpp index c25b0142..b224ab7e 100644 --- a/src/query/recollq.cpp +++ b/src/query/recollq.cpp @@ -38,6 +38,7 @@ #include "transcode.h" #include "textsplit.h" #include "smallut.h" +#include "chrono.h" #include "base64.h" using namespace std; diff --git a/src/rcldb/expansiondbs.cpp b/src/rcldb/expansiondbs.cpp index 5df513e6..2b01f9a8 100644 --- a/src/rcldb/expansiondbs.cpp +++ b/src/rcldb/expansiondbs.cpp @@ -18,10 +18,12 @@ #include "autoconfig.h" +#include MEMORY_INCLUDE + #include "debuglog.h" #include "utf8iter.h" #include "smallut.h" -#include MEMORY_INCLUDE +#include "chrono.h" #include "textsplit.h" #include "xmacros.h" #include "rcldb.h" diff --git a/src/rcldb/rclabstract.cpp b/src/rcldb/rclabstract.cpp index 2d7111c7..6f16f41b 100644 --- a/src/rcldb/rclabstract.cpp +++ b/src/rcldb/rclabstract.cpp @@ -29,6 +29,7 @@ #include "searchdata.h" #include "utf8iter.h" #include "hldata.h" +#include "chrono.h" using namespace std; diff --git a/src/rcldb/rcldb.cpp b/src/rcldb/rcldb.cpp index 7be84f5a..a5457672 100644 --- a/src/rcldb/rcldb.cpp +++ b/src/rcldb/rcldb.cpp @@ -43,6 +43,7 @@ using namespace std; #include "conftree.h" #include "pathut.h" #include "smallut.h" +#include "chrono.h" #include "utf8iter.h" #include "searchdata.h" #include "rclquery.h" diff --git a/src/rcldb/rclquery.cpp b/src/rcldb/rclquery.cpp index a747efb6..7d662573 100644 --- a/src/rcldb/rclquery.cpp +++ b/src/rcldb/rclquery.cpp @@ -34,6 +34,7 @@ #include "rclquery_p.h" #include "conftree.h" #include "smallut.h" +#include "chrono.h" #include "searchdata.h" #include "unacpp.h" diff --git a/src/utils/Makefile b/src/utils/Makefile index 27c8de6e..c9407a74 100644 --- a/src/utils/Makefile +++ b/src/utils/Makefile @@ -14,6 +14,12 @@ pxattr: $(PXATTROBJS) trpxattr.o : pxattr.cpp $(CXX) -c $(CXXFLAGS) -DTEST_PXATTR -o $@ pxattr.cpp +CHRONOOBJS = trchrono.o chrono.o +trchrono: $(CHRONOOBJS) + $(CXX) -o chrono $(CHRONOOBJS) +trchrono.o : chrono.cpp + $(CXX) -c $(CXXFLAGS) -DTEST_CHRONO -o $@ chrono.cpp + PTMUTEXOBJS = ptmutex.o ptmutex: $(PTMUTEXOBJS) $(CXX) -o ptmutex $(PTMUTEXOBJS) $(LIBRECOLL) diff --git a/src/utils/chrono.cpp b/src/utils/chrono.cpp new file mode 100644 index 00000000..8d711070 --- /dev/null +++ b/src/utils/chrono.cpp @@ -0,0 +1,289 @@ +/* Copyright (C) 2014 J.F.Dockes + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ +#ifndef TEST_CHRONO +#include "autoconfig.h" + +#include +#include + +#include "chrono.h" + +using namespace std; + +#ifndef CLOCK_REALTIME +typedef int clockid_t; +#define CLOCK_REALTIME 1 +#endif + + +#define SECONDS(TS1, TS2) \ + (float((TS2).tv_sec - (TS1).tv_sec) + \ + float((TS2).tv_nsec - (TS1).tv_nsec) * 1e-9) + +#define MILLIS(TS1, TS2) \ + ((long long)((TS2).tv_sec - (TS1).tv_sec) * 1000LL + \ + ((TS2).tv_nsec - (TS1).tv_nsec) / 1000000) + +#define MICROS(TS1, TS2) \ + ((long long)((TS2).tv_sec - (TS1).tv_sec) * 1000000LL + \ + ((TS2).tv_nsec - (TS1).tv_nsec) / 1000) + +#define NANOS(TS1, TS2) \ + ((long long)((TS2).tv_sec - (TS1).tv_sec) * 1000000000LL + \ + ((TS2).tv_nsec - (TS1).tv_nsec)) + + + +// Using clock_gettime() is nice because it gives us ns res and it helps with +// computing threads work times, but it's also a pita because it forces linking +// with -lrt. So keep it non-default, special development only. +// #define USE_CLOCK_GETTIME + +// And wont' bother with gettime() on these. +#if defined(__APPLE__) || defined(_WIN32) +#undef USE_CLOCK_GETTIME +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#include +#include // portable: uint64_t MSVC: __int64 + +// MSVC defines this in winsock2.h!? +typedef struct timeval { + long tv_sec; + long tv_usec; +} timeval; + +int gettimeofday(struct timeval * tp, struct timezone * tzp) +{ + // Note: some broken versions only have 8 trailing zero's, the + // correct epoch has 9 trailing zero's + static const uint64_t EPOCH = ((uint64_t) 116444736000000000ULL); + + SYSTEMTIME system_time; + FILETIME file_time; + uint64_t time; + + GetSystemTime( &system_time ); + SystemTimeToFileTime( &system_time, &file_time ); + time = ((uint64_t)file_time.dwLowDateTime ) ; + time += ((uint64_t)file_time.dwHighDateTime) << 32; + + tp->tv_sec = (long) ((time - EPOCH) / 10000000L); + tp->tv_usec = (long) (system_time.wMilliseconds * 1000); + return 0; +} +#else // -> Not _WIN32 +#ifndef USE_CLOCK_GETTIME +// Using gettimeofday then, needs struct timeval +#include +#endif +#endif + + + +// We use gettimeofday instead of clock_gettime for now and get only +// uS resolution, because clock_gettime is more configuration trouble +// than it's worth +static void gettime(int +#ifdef USE_CLOCK_GETTIME + clk_id +#endif + , Chrono::TimeSpec *ts) +{ +#ifdef USE_CLOCK_GETTIME + struct timespec mts; + clock_gettime(clk_id, &mts); + ts->tv_sec = mts.tv_sec; + ts->tv_nsec = mts.tv_nsec; +#else + struct timeval tv; + gettimeofday(&tv, 0); + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec * 1000; +#endif +} +///// End system interface + +// Note: this not protected against multithread access and not +// reentrant, but this is mostly debug code, and it won't crash, just +// show bad results. Also the frozen thing is not used that much +Chrono::TimeSpec Chrono::o_now; + +void Chrono::refnow() +{ + gettime(CLOCK_REALTIME, &o_now); +} + +Chrono::Chrono() +{ + restart(); +} + +// Reset and return value before rest in milliseconds +long Chrono::restart() +{ + TimeSpec now; + gettime(CLOCK_REALTIME, &now); + long ret = MILLIS(m_orig, now); + m_orig = now; + return ret; +} + +long Chrono::urestart() +{ + TimeSpec now; + gettime(CLOCK_REALTIME, &now); + long ret = MICROS(m_orig, now); + m_orig = now; + return ret; +} + +// Get current timer value, milliseconds +long Chrono::millis(bool frozen) +{ + if (frozen) { + return MILLIS(m_orig, o_now); + } else { + TimeSpec now; + gettime(CLOCK_REALTIME, &now); + return MILLIS(m_orig, now); + } +} + +// +long Chrono::micros(bool frozen) +{ + if (frozen) { + return MICROS(m_orig, o_now); + } else { + TimeSpec now; + gettime(CLOCK_REALTIME, &now); + return MICROS(m_orig, now); + } +} + +long long Chrono::amicros() const +{ + TimeSpec ts; + ts.tv_sec = 0; + ts.tv_nsec = 0; + return MICROS(ts, m_orig); +} + +// +long long Chrono::nanos(bool frozen) +{ + if (frozen) { + return NANOS(m_orig, o_now); + } else { + TimeSpec now; + gettime(CLOCK_REALTIME, &now); + return NANOS(m_orig, now); + } +} + +float Chrono::secs(bool frozen) +{ + if (frozen) { + return SECONDS(m_orig, o_now); + } else { + TimeSpec now; + gettime(CLOCK_REALTIME, &now); + return SECONDS(m_orig, now); + } +} + +#else + +///////////////////// test driver + + +#include +#include +#include +#include + +#include + +#include "chrono.h" + +using namespace std; + +static char *thisprog; +static void +Usage(void) +{ + fprintf(stderr, "Usage : %s \n", thisprog); + exit(1); +} + +Chrono achrono; +Chrono rchrono; + +void +showsecs(long msecs) +{ + fprintf(stderr, "%3.5f S", ((float)msecs) / 1000.0); +} + +void +sigint(int sig) +{ + signal(SIGINT, sigint); + signal(SIGQUIT, sigint); + + fprintf(stderr, "Absolute interval: "); + showsecs(achrono.millis()); + fprintf(stderr, ". Relative interval: "); + showsecs(rchrono.restart()); + cerr << " Abs micros: " << achrono.amicros() << + " Relabs micros: " << rchrono.amicros() - 1430477861905884LL + << endl; + fprintf(stderr, ".\n"); + if (sig == SIGQUIT) { + exit(0); + } +} + +int main(int argc, char **argv) +{ + + thisprog = argv[0]; + argc--; + argv++; + + if (argc != 0) { + Usage(); + } + + for (int i = 0; i < 50000000; i++); + + cerr << "Start secs: " << achrono.secs() << endl; + + fprintf(stderr, "Type ^C for intermediate result, ^\\ to stop\n"); + signal(SIGINT, sigint); + signal(SIGQUIT, sigint); + achrono.restart(); + rchrono.restart(); + while (1) { + pause(); + } +} + +#endif /*TEST_CHRONO*/ diff --git a/src/utils/chrono.h b/src/utils/chrono.h new file mode 100644 index 00000000..2dc08c38 --- /dev/null +++ b/src/utils/chrono.h @@ -0,0 +1,62 @@ +/* Copyright (C) 2014 J.F.Dockes + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the + * Free Software Foundation, Inc., + * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + */ + +#ifndef _CHRONO_H_INCLUDED_ +#define _CHRONO_H_INCLUDED_ + +#include + +/** Easy interface to measuring time intervals */ +class Chrono { +public: + /** Initialize, setting the origin time */ + Chrono(); + + /** Re-store current time and return mS since init or last call */ + long restart(); + /** Re-store current time and return uS since init or last call */ + long urestart(); + + /** Snapshot current time to static storage */ + static void refnow(); + + /** Return interval value in various units. + * + * If frozen is set this gives the time since the last refnow call + * (this is to allow for using one actual system call to get + values from many chrono objects, like when examining timeouts + in a queue + */ + long long nanos(bool frozen = false); + long micros(bool frozen = false); + long millis(bool frozen = false); + float secs(bool frozen = false); + + /** Return the absolute value of the current origin */ + long long amicros() const; + + struct TimeSpec { + time_t tv_sec; /* Time in seconds */ + long tv_nsec; /* And nanoseconds (< 10E9) */ + }; + +private: + TimeSpec m_orig; + static TimeSpec o_now; +}; + +#endif /* _CHRONO_H_INCLUDED_ */ diff --git a/src/utils/circache.cpp b/src/utils/circache.cpp index f3b77781..deb2959b 100644 --- a/src/utils/circache.cpp +++ b/src/utils/circache.cpp @@ -29,6 +29,8 @@ #include #include +#include "chrono.h" + #ifndef _WIN32 #include #else diff --git a/src/utils/smallut.cpp b/src/utils/smallut.cpp index 9314d543..2a23c962 100644 --- a/src/utils/smallut.cpp +++ b/src/utils/smallut.cpp @@ -745,181 +745,6 @@ string breakIntoLines(const string& in, unsigned int ll, return oq; } -//////////////////// - -#if 0 -// Internal redefinition of system time interface to help with dependancies -struct m_timespec { - time_t tv_sec; - long tv_nsec; -}; -#endif - -#ifndef CLOCK_REALTIME -typedef int clockid_t; -#define CLOCK_REALTIME 1 -#endif - -#define MILLIS(TV) ( (long)(((TV).tv_sec - m_secs) * 1000L + \ - ((TV).tv_nsec - m_nsecs) / 1000000)) -#define MICROS(TV) ( (long)(((TV).tv_sec - m_secs) * 1000000L + \ - ((TV).tv_nsec - m_nsecs) / 1000)) -#define NANOS(TV) ( (long long)(((TV).tv_sec - m_secs) * 1000000000LL + \ - ((TV).tv_nsec - m_nsecs))) - -// Using clock_gettime() is nice because it gives us ns res and it helps with -// computing threads work times, but it's also a pita because it forces linking -// with -lrt. So keep it optional. And not on the mac anyway -// #define USE_CLOCK_GETTIME - -#ifdef __APPLE__ -#undef USE_CLOCK_GETTIME -#endif - -#ifdef WIN32 -#include "safewindows.h" -// Note: struct timespec is defined by pthread.h (from pthreads-w32) -#ifndef CLOCK_REALTIME -#define CLOCK_REALTIME 0 -#endif - -LARGE_INTEGER getFILETIMEoffset() -{ - SYSTEMTIME s; - FILETIME f; - LARGE_INTEGER t; - - s.wYear = 1970; - s.wMonth = 1; - s.wDay = 1; - s.wHour = 0; - s.wMinute = 0; - s.wSecond = 0; - s.wMilliseconds = 0; - SystemTimeToFileTime(&s, &f); - t.QuadPart = f.dwHighDateTime; - t.QuadPart <<= 32; - t.QuadPart |= f.dwLowDateTime; - return (t); -} - -int clock_gettime(int X, struct timespec *tv) -{ - LARGE_INTEGER t; - FILETIME f; - double microseconds; - static LARGE_INTEGER offset; - static double frequencyToMicroseconds; - static int initialized = 0; - static BOOL usePerformanceCounter = 0; - - if (!initialized) { - LARGE_INTEGER performanceFrequency; - initialized = 1; - usePerformanceCounter = QueryPerformanceFrequency(&performanceFrequency); - if (usePerformanceCounter) { - QueryPerformanceCounter(&offset); - frequencyToMicroseconds = (double)performanceFrequency.QuadPart / 1000000.; - } - else { - offset = getFILETIMEoffset(); - frequencyToMicroseconds = 10.; - } - } - if (usePerformanceCounter) QueryPerformanceCounter(&t); - else { - GetSystemTimeAsFileTime(&f); - t.QuadPart = f.dwHighDateTime; - t.QuadPart <<= 32; - t.QuadPart |= f.dwLowDateTime; - } - - t.QuadPart -= offset.QuadPart; - microseconds = (double)t.QuadPart / frequencyToMicroseconds; - t.QuadPart = (long long)microseconds; - tv->tv_sec = t.QuadPart / 1000000; - tv->tv_nsec = (t.QuadPart % 1000000) * 1000; - return (0); -} -#define USE_CLOCK_GETTIME -#else /* -> !_WIN32 */ - -#ifndef USE_CLOCK_GETTIME -#include -#endif - -#endif - -static void gettime(clockid_t clk_id, struct timespec *ts) -{ -#ifndef USE_CLOCK_GETTIME - struct timeval tv; - gettimeofday(&tv, 0); - ts->tv_sec = tv.tv_sec; - ts->tv_nsec = tv.tv_usec * 1000; -#else - clock_gettime(clk_id, ts); -#endif -} -///// End system interface - -// Note: this not protected against multithread access and not reentrant, but -// this is mostly debug code, and it won't crash, just show bad results. Also -// the frozen thing is not used that much -static timespec frozen_tv; -void Chrono::refnow() -{ - gettime(CLOCK_REALTIME, &frozen_tv); -} - -Chrono::Chrono() -{ - restart(); -} - -// Reset and return value before rest in milliseconds -time_t Chrono::restart() -{ - struct timespec tv; - gettime(CLOCK_REALTIME, &tv); - time_t ret = MILLIS(tv); - m_secs = tv.tv_sec; - m_nsecs = tv.tv_nsec; - return ret; -} - -// Get current timer value, milliseconds -time_t Chrono::millis(int frozen) -{ - return nanos() / 1000000; -} - -// -time_t Chrono::micros(int frozen) -{ - return nanos() / 1000; -} - -time_t Chrono::nanos(int frozen) -{ - if (frozen) { - return NANOS(frozen_tv); - } else { - struct timespec tv; - gettime(CLOCK_REALTIME, &tv); - return NANOS(tv); - } -} - -double Chrono::secs(int frozen) -{ - struct timespec tv; - gettime(CLOCK_REALTIME, &tv); - double secs = (double)(frozen?frozen_tv.tv_sec:tv.tv_sec - m_secs); - double nsecs = (double)(frozen?frozen_tv.tv_nsec:tv.tv_nsec - m_nsecs); - return secs + nsecs * 1e-9; -} - // Date is Y[-M[-D]] static bool parsedate(vector::const_iterator& it, vector::const_iterator end, DateInterval *dip) diff --git a/src/utils/smallut.h b/src/utils/smallut.h index de32586f..9b2a4b04 100644 --- a/src/utils/smallut.h +++ b/src/utils/smallut.h @@ -158,30 +158,6 @@ void catstrerror(string *reason, const char *what, int _errno); struct tm; time_t portable_timegm(struct tm *tm); -/** Compute times to help with perf issues */ -class Chrono { - public: - Chrono(); - /** Reset origin */ - time_t restart(); - /** Snapshot current time */ - static void refnow(); - /** Get current elapsed since creation or restart - * - * @param frozen give time since the last refnow call (this is to - * allow for using one actual system call to get values from many - * chrono objects, like when examining timeouts in a queue) - */ - time_t millis(int frozen = 0); - time_t ms() {return millis();} - time_t micros(int frozen = 0); - time_t nanos(int frozen = 0); - double secs(int frozen = 0); - private: - time_t m_secs; - time_t m_nsecs; -}; - /** Temp buffer with automatic deallocation */ struct TempBuf { TempBuf() diff --git a/src/windows/qmkrecoll/librecoll.pro b/src/windows/qmkrecoll/librecoll.pro index ecb16ed8..11b31486 100644 --- a/src/windows/qmkrecoll/librecoll.pro +++ b/src/windows/qmkrecoll/librecoll.pro @@ -79,6 +79,7 @@ SOURCES += \ ../../unac/unac.cpp \ ../../utils/appformime.cpp \ ../../utils/base64.cpp \ +../../utils/chrono.cpp \ ../../utils/circache.cpp \ ../../utils/conftree.cpp \ ../../utils/copyfile.cpp \