Use a custom thread + sleep_for instead of a C timer.
authorMilian Wolff <mail@milianw.de>
Tue, 9 Dec 2014 19:27:47 +0000 (20:27 +0100)
committerMilian Wolff <mail@milianw.de>
Tue, 9 Dec 2014 19:51:15 +0000 (20:51 +0100)
This makes re-attaching work without deadlocks in timer_delete
for me. And we can clean the code up even more now:

Much less code, yet still more accurate. The overhead is negleglible
in my tests. And this makes it trivial for the future to let users
configure the interval themselves.

heaptrack_inject.cpp
heaptrack_print.cpp
libheaptrack.cpp
timer.h [deleted file]

index 9e404a7..f4f37fd 100644 (file)
@@ -263,7 +263,6 @@ void heaptrack_inject(const char *outputFileName)
         malloc_info(0, out);
         fprintf(out, "\nA END_MALLOC_INFO\n");
     }, [] () {
-        printf("shutting down heaptrack\n");
         bool do_shutdown = true;
         dl_iterate_phdr(&iterate_phdrs, &do_shutdown);
     });
index 937ab14..9907518 100644 (file)
@@ -533,7 +533,6 @@ struct AccumulatedTraceData
                 // comment or empty line
                 continue;
             } else if (reader.mode() == 'c') {
-                // TODO: implement time tracking
                 size_t newStamp = 0;
                 if (!(reader >> newStamp)) {
                     cerr << "Failed to read time stamp: " << reader.line() << endl;
@@ -693,7 +692,7 @@ private:
                   << "time_unit: s\n";
     }
 
-    void writeMassifSnapshot(size_t snapshot, bool isLast)
+    void writeMassifSnapshot(size_t timeStamp, bool isLast)
     {
         // the heap consumption we annotate this snapshot with
         size_t heapSize = 0;
@@ -714,7 +713,7 @@ private:
             << "#-----------\n"
             << "snapshot=" << massifSnapshotId << '\n'
             << "#-----------\n"
-            << "time=" << double(snapshot) * 0.01 << '\n'
+            << "time=" << (0.001 * timeStamp) << '\n'
             << "mem_heap_B=" << heapSize << '\n'
             << "mem_heap_extra_B=0\n"
             << "mem_stacks_B=0\n";
index 3a00403..8c3ad66 100644 (file)
 #include <memory>
 #include <unordered_set>
 #include <mutex>
+#include <thread>
 
 #include <boost/algorithm/string/replace.hpp>
 
 #include "tracetree.h"
-#include "timer.h"
 
 /**
  * uncomment this to get extended debug code for known pointers
@@ -166,15 +166,35 @@ void updateModuleCache(FILE* out)
 
 struct Data
 {
-    void handleMalloc(void* ptr, size_t size, const Trace &trace, FILE* out)
+    Data()
     {
-        if (lastTimerElapsed != timer.timesElapsed()) {
-            lastTimerElapsed = timer.timesElapsed();
-            if (fprintf(out, "c %lx\n", lastTimerElapsed) < 0) {
-                heaptrack_stop();
-                return;
+        timerThread = thread([&] () {
+            using clock = chrono::steady_clock;
+            const auto start = clock::now();
+            while (!stopTimerThread) {
+                // TODO: make interval customizable
+                this_thread::sleep_for(chrono::milliseconds(10));
+                auto elapsed = chrono::duration_cast<chrono::milliseconds>(clock::now() - start);
+
+                if (FILE* out = outputHandle.load()) {
+                    LockGuard lock(out);
+                    if (fprintf(out, "c %lx\n", elapsed.count()) < 0) {
+                        heaptrack_stop();
+                        return;
+                    }
+                }
             }
-        }
+        });
+    }
+
+    ~Data()
+    {
+        stopTimerThread = true;
+        timerThread.join();
+    }
+
+    void handleMalloc(void* ptr, size_t size, const Trace &trace, FILE* out)
+    {
         if (moduleCacheDirty) {
             updateModuleCache(out);
         }
@@ -208,8 +228,8 @@ struct Data
 
     TraceTree traceTree;
 
-    size_t lastTimerElapsed = 0;
-    Timer timer;
+    atomic<bool> stopTimerThread;
+    thread timerThread;
 
 #ifdef DEBUG_MALLOC_PTRS
     unordered_set<void*> known;
@@ -337,7 +357,6 @@ void heaptrack_stop()
     HandleGuard guard;
     if (outputHandle) {
         flockfile(outputHandle.load());
-        printf("shutting down heaptrack!\n");
         fclose(outputHandle.exchange(nullptr));
         delete data.exchange(nullptr);
         if (auto stop = s_stopCallback.exchange(nullptr)) {
diff --git a/timer.h b/timer.h
deleted file mode 100644 (file)
index 6ff3ea5..0000000
--- a/timer.h
+++ /dev/null
@@ -1,87 +0,0 @@
-/*
- * Copyright 2014 Milian Wolff <mail@milianw.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU Library 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.,
- * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-#ifndef TIMER_H
-#define TIMER_H
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <stdio.h>
-#include <signal.h>
-#include <time.h>
-#include <cassert>
-
-#include <limits>
-#include <atomic>
-
-class Timer
-{
-public:
-    Timer()
-        : m_timesElapsed(0)
-        , m_timerId(0)
-    {
-        sigevent sev;
-        sev.sigev_notify = SIGEV_THREAD;
-        sev.sigev_notify_function = &Timer::handler;
-        sev.sigev_notify_attributes = nullptr;
-        sev.sigev_value.sival_ptr = this;
-        if (timer_create(CLOCK_REALTIME, &sev, &m_timerId) == -1) {
-            fprintf(stderr, "Failed to call timer_create in %s:%d: %s",
-                    __FILE__, __LINE__, strerror(errno));
-            return;
-        }
-
-        /* Start/Stop the timer */
-        itimerspec its;
-        its.it_value.tv_sec = 0;
-        its.it_value.tv_nsec = 10 * 1000 * 1000;
-        its.it_interval.tv_sec = its.it_value.tv_sec;
-        its.it_interval.tv_nsec = its.it_value.tv_nsec;
-
-        if (timer_settime(m_timerId, 0, &its, nullptr) == -1) {
-            fprintf(stderr, "Failed to call timer_settime in %s:%d: %s",
-                    __FILE__, __LINE__, strerror(errno));
-            return;
-        }
-    }
-
-    ~Timer()
-    {
-        timer_delete(m_timerId);
-    }
-
-    size_t timesElapsed() const
-    {
-        return m_timesElapsed;
-    }
-
-private:
-    static void handler(union sigval value)
-    {
-        Timer* timer = static_cast<Timer*>(value.sival_ptr);
-
-        timer->m_timesElapsed += timer_getoverrun(timer->m_timerId) + 1;
-    }
-
-    std::atomic<size_t> m_timesElapsed;
-    timer_t m_timerId;
-};
-
-#endif