summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLennart Poettering <lennart@poettering.net>2005-01-15 21:58:41 +0000
committerLennart Poettering <lennart@poettering.net>2005-01-15 21:58:41 +0000
commit836305f518d6f7d84b3b23461586043369c8e908 (patch)
tree9c9d162cd593cb7b550e71124e29a7d881400708
parentb73ba72e71334f396175c68e060ea13db0ce6b8a (diff)
parent2413614d3bc435cd09e425fa34068e4a333f0495 (diff)
rename heatload to trunk
git-svn-id: file:///home/lennart/svn/public/heatload/trunk@7 3bca8330-beed-0310-b360-ea58cfc96e4b
-rw-r--r--Makefile46
-rw-r--r--README.in71
-rw-r--r--RELEASES8
-rw-r--r--heatload.cc447
4 files changed, 572 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..2f96dd2
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,46 @@
+VERSION=0.3
+CXXFLAGS=-Wall -W -pipe -O2 -g -DVERSION=\"$(VERSION)\" `pkg-config --cflags gtkmm-2.4 gdkmm-2.4`
+TAR=heatload-$(VERSION).tar.gz
+SOURCES=heatload.cc
+BINARY=heatload
+LIBS=`pkg-config --libs gtkmm-2.4 gdkmm-2.4`
+PACKAGE=heatload
+
+all: $(BINARY)
+
+$(BINARY): $(SOURCES)
+ $(CXX) $(CXXFLAGS) $(SOURCES) -o $(BINARY) $(LIBS)
+
+strip: $(BINARY)
+ @du -h $(BINARY)
+ strip -s $(BINARY)
+ @du -h $(BINARY)
+
+clean:
+ rm -f $(BINARY)
+ rm -f *~ *.bak *.tar.gz
+
+install: strip
+ install -g root -o root -m 555 $(BINARY) /usr/local/bin
+
+deinstall:
+ rm -f /usr/local/bin/$(BINARY)
+
+README: README.in
+ sed s/VERSION/$(VERSION)/ < README.in > README
+
+index.html: README
+ txt2html -t "$(PACKAGE) $(VERSION)" < README > index.html
+
+html: index.html
+
+$(TAR): clean README
+ tar -C.. --exclude=$(PACKAGE)/$(TAR) -czvf $(TAR) $(PACKAGE)
+
+tar: $(TAR)
+
+web: $(TAR) README
+ cp README $(TAR) ../../homepage/lennart/projects/$(PACKAGE)/ && $(MAKE) -C ../../homepage/lennart/projects/$(PACKAGE)
+
+upload: web
+ $(MAKE) -C ../../homepage/lennart upload
diff --git a/README.in b/README.in
new file mode 100644
index 0000000..6755576
--- /dev/null
+++ b/README.in
@@ -0,0 +1,71 @@
+heatload VERSION - CPU Load and ACPI Temperature Monitor
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+Copyright 2002
+Lennart Poettering <mz686561746c6f6164@poettering.de>
+
+---------------------------------------------------------------------
+
+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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+---------------------------------------------------------------------
+
+This Gnome utility produces nice looking realtime graphs for the
+current CPU load and ACPI temperature of your Linux machine. It is
+nice for monitoring the direct relation of the former to the latter.
+
+The reason I developed this program was that the ACPI implementation
+of my laptop seems to be broken, and I needed a simple way to
+determine when the machines became too hot.
+
+Requirements
+------------
+
+As of version 0.1 you need a Linux kernel 2.4 with a fairly recent
+ACPI patch. (I used 20020308) Without this patch, the utility will not
+recognize your temperature sensor. Starting with 0.2, I added support
+for plain 2.4.18-Kernels (and some kernel versions prior) with ACPI
+20011018 based on a patch by Ian Morgan. lm_sensor-devices are not
+supported. (Somebody wants to send me a patch?)
+
+For compiling you need a recent g++ with Gtk-- and Gnome--
+installed. I did my development with 1.2.8 resp. 1.2.2.
+
+Development
+-----------
+
+Development was done under Debian GNU Linux Woody for i386 from March
+2002. The used machine was a Medion 9580-F laptop.
+
+Installation
+------------
+
+Run "make" for compiling the program. You might want to install it
+permanently on your system by issuing "make install" as root. This
+install the heatload executable to /usr/local/bin/. For removing this
+installation you might want to try "make deinstall" as root.
+
+Internet
+--------
+
+You may find up to date releases of this utility on
+ http://www.stud.uni-hamburg.de/users/lennart/projects/heatload/
+
+You may download this release from
+ http://www.stud.uni-hamburg.de/users/lennart/projects/heatload/heatload-VERSION.tar.gz
+
+---------------------------------------------------------------------
+
+Lennart Poettering <mz686561746c6f6164@poettering.de>, 2002
diff --git a/RELEASES b/RELEASES
new file mode 100644
index 0000000..136e155
--- /dev/null
+++ b/RELEASES
@@ -0,0 +1,8 @@
+heatload 0.2:
+
+ Compilation fixes for libsigc++ on Ximian
+ Support for ACPI 20011018
+
+heatload 0.1:
+
+ Initial Release
diff --git a/heatload.cc b/heatload.cc
new file mode 100644
index 0000000..21b8787
--- /dev/null
+++ b/heatload.cc
@@ -0,0 +1,447 @@
+#include <gtkmm.h>
+#include <gdkmm.h>
+
+#include <deque>
+
+#include <stdio.h>
+#include <unistd.h>
+#include <dirent.h>
+
+#define METER_WIDTH 300
+#define METER_HEIGHT 100
+
+class MeterStruct {
+
+protected:
+ std::deque<gint> data_deque;
+ glong last_time;
+ bool modified;
+
+public:
+ MeterStruct() : last_time(0), modified(true) {};
+
+ void add_value(gint b);
+ bool is_modified() { return modified; }
+ void reset_modified() { modified = false; }
+
+ void draw(const Glib::RefPtr<Gdk::Drawable> &d, const Glib::RefPtr<const Gdk::GC> &g);
+};
+
+void MeterStruct::add_value(gint b) {
+ GTimeVal tv;
+ glong n;
+
+ g_get_current_time(&tv);
+
+ if (last_time == 0)
+ n = 1;
+ else if (last_time == tv.tv_sec) {
+ data_deque.pop_front();
+ n = 1;
+ } else
+ n = tv.tv_sec - last_time;
+
+ last_time = tv.tv_sec;
+
+ for (; n > 0; n --)
+ data_deque.push_back(b);
+
+ while (data_deque.size() > METER_WIDTH)
+ data_deque.pop_front();
+
+ modified = true;
+}
+
+void MeterStruct::draw(const Glib::RefPtr<Gdk::Drawable> &d, const Glib::RefPtr<const Gdk::GC> &g) {
+ std::deque<gint> copy = data_deque;
+
+ int width, height;
+ d->get_size(width, height);
+
+ gint lx = -1, ly = -1;
+ for (gint x = width-1; x >= 0; x--) {
+ if (copy.size() == 0)
+ break;
+
+ gint b = copy.back();
+ gint y = (100-b)*(height-1)/100;
+
+ if (lx == -1)
+ d->draw_point(g, x, y);
+ else
+ d->draw_line(g, lx, ly, x, y);
+
+ lx = x;
+ ly = y;
+
+ copy.pop_back();
+ }
+}
+
+MeterStruct load_meter;
+MeterStruct temperature_meter;
+
+class GraphDrawingArea : public Gtk::DrawingArea {
+
+public:
+ GraphDrawingArea();
+
+ void refresh_pixmap();
+
+protected:
+ virtual bool on_expose_event(GdkEventExpose* event);
+
+ Glib::RefPtr<Gdk::Pixmap> pixmap;
+
+ Gdk::Color color0;
+ Gdk::Color color1;
+ Gdk::Color color2;
+};
+
+GraphDrawingArea::GraphDrawingArea():
+ Gtk::DrawingArea(), color0("black"), color1("green"), color2("tomato") {
+ set_size_request(METER_WIDTH, METER_HEIGHT);
+}
+
+bool GraphDrawingArea::on_expose_event(GdkEventExpose*) {
+
+ if (!pixmap)
+ refresh_pixmap();
+
+ if (pixmap) {
+ Glib::RefPtr<Gdk::Window> win = get_window();
+ Glib::RefPtr<Gdk::GC> gc = get_style()->get_fg_gc(get_state());
+ win->draw_drawable(gc, pixmap, 0, 0, 0, 0);
+ }
+
+ return true;
+}
+
+void GraphDrawingArea::refresh_pixmap() {
+ Glib::RefPtr<Gdk::Window> win = get_window();
+
+ if (!pixmap || load_meter.is_modified() || temperature_meter.is_modified()) {
+ int width, height, width2, height2;
+
+ load_meter.reset_modified();
+ temperature_meter.reset_modified();
+
+ win->get_size(width, height);
+ if (pixmap)
+ pixmap->get_size(width2, height2);
+
+ if (!pixmap || width != width2 || height != height2) {
+ pixmap = Gdk::Pixmap::create(win, width, height);
+
+ Glib::RefPtr<Gdk::Colormap> cmap = win->get_colormap();
+ cmap->alloc_color(color0);
+ cmap->alloc_color(color1);
+ cmap->alloc_color(color2);
+ }
+
+ Glib::RefPtr<Gdk::GC> gc = Gdk::GC::create(pixmap);
+
+ gc->set_foreground(color0);
+ pixmap->draw_rectangle(gc, TRUE, 0, 0, width, height);
+
+ gc->set_foreground(color1);
+ load_meter.draw(pixmap, gc);
+
+ gc->set_foreground(color2);
+ temperature_meter.draw(pixmap, gc);
+ }
+}
+
+class MainWindow : public Gtk::Window {
+
+protected:
+
+ Gtk::VBox vbox;
+ Gtk::Label label;
+ Gtk::Label cpu_label, temperature_label;
+ Gtk::Frame frame;
+ GraphDrawingArea drawing_area;
+ Gtk::HBox hbox;
+
+public:
+ MainWindow();
+
+ virtual void refresh();
+ virtual void update_values(gint v1, gint v2);
+ virtual bool on_delete_event(GdkEventAny* event);
+};
+
+
+MainWindow::MainWindow():
+ vbox(false, 5),
+ hbox(true, 5) {
+
+ set_border_width(5);
+ set_title("Heatload");
+
+ label.set_markup(/*"<b><span size=\"x-large\" face=\"Serif\">Heatload "VERSION"</span></b>\n"*/
+ "<span foreground=\"darkgreen\">Green</span>: CPU Load; "
+ "<span foreground=\"darkred\">Red</span>: ACPI CPU Temperature\n"
+ "<i>(Ranges from 0% to 100%, resp. 0&#176;C to 100&#176;C)</i>");
+
+ label.set_justify(Gtk::JUSTIFY_CENTER);
+ label.set_alignment(.5, .5);
+
+ cpu_label.set_justify(Gtk::JUSTIFY_CENTER);
+ cpu_label.set_alignment(0, 0);
+
+ temperature_label.set_justify(Gtk::JUSTIFY_LEFT);
+ temperature_label.set_alignment(0, 0);
+
+ frame.set_shadow_type(Gtk::SHADOW_IN);
+ frame.add(drawing_area);
+
+ vbox.pack_start(label, false, true);
+ vbox.pack_start(frame, true, true);
+
+ hbox.pack_start(cpu_label, false, true);
+ hbox.pack_start(temperature_label, false, true);
+
+ vbox.pack_start(hbox, false, true);
+
+ add(vbox);
+
+ show_all();
+}
+
+void MainWindow::refresh() {
+ drawing_area.refresh_pixmap();
+
+ Gdk::Rectangle r;
+ r.set_x(0);
+ r.set_y(0);
+ r.set_width(drawing_area.get_width());
+ r.set_height(drawing_area.get_height());
+
+ drawing_area.get_window()->invalidate_rect(r, false);
+}
+
+bool MainWindow::on_delete_event(GdkEventAny* event) {
+ Gtk::Main::quit();
+ return Gtk::Window::on_delete_event(event);
+}
+
+void MainWindow::update_values(gint v1, gint v2) {
+ char txt[256];
+ static gint ov1 = -1;
+ static gint ov2 = -1;
+
+ if (ov1 != v1) {
+ snprintf(txt, sizeof(txt), "<span foreground=\"darkgreen\">CPU Load</span>: %i%%", v1);
+ cpu_label.set_markup(txt);
+ ov1 = v1;
+ }
+
+ if (ov2 != v2) {
+ snprintf(txt, sizeof(txt), "<span foreground=\"darkred\">CPU Temperature</span>: %i&#176;C", v2);
+ temperature_label.set_markup(txt);
+ ov2 = v2;
+ }
+
+}
+
+void failure(const Glib::ustring &txt) {
+ static Gtk::MessageDialog msgbox("Could not read data from /proc file system:\n<b>"+txt+"</b>", true, Gtk::MESSAGE_ERROR);
+ static bool running = false;
+
+ if (running)
+ return;
+
+ running = true;
+ msgbox.run();
+ running = false;
+}
+
+gint get_load_value() {
+ char txt[256];
+ char*p;
+ static int ct[2][4] = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 } };
+ static int n = 0;
+ int d[4];
+ int t, fd;
+ float v;
+ static FILE*f = NULL;
+
+ if (!f && !(f = fopen("/proc/stat", "r"))) {
+ failure("Unable to open kernel statistics file.");
+ goto fail;
+ }
+
+ if (!(p = fgets(txt, sizeof(txt), f))) {
+ failure("Unable to read from kernel statistics file.");
+ goto fail;
+ }
+
+ fd = dup(fileno(f));
+ fclose(f);
+ f = fdopen(fd, "r");
+ g_assert(f);
+ fseek(f, 0, SEEK_SET);
+
+ if (strlen(p) <= 5) {
+ failure("Parse failure");
+ goto fail;
+ }
+
+ sscanf(p+5, "%u %u %u %u", &ct[n][0], &ct[n][1], &ct[n][2], &ct[n][3]);
+
+ t = 0;
+
+ for (int i = 0; i < 4; i++)
+ t += (d[i] = abs(ct[n][i] - ct[1-n][i]));
+
+ v = (t - d[3])/(float) t;
+
+ n = 1-n;
+
+ return (gint) (v*100);
+
+fail:
+ if (f) {
+ fclose(f);
+ f = NULL;
+ }
+
+ return -1;
+}
+
+FILE * fopen_first(const char *pfx, const char *sfx, const char *m) {
+ g_assert(pfx);
+ g_assert(sfx);
+ g_assert(m);
+
+ DIR *dir;
+ struct dirent *de;
+ char fn[PATH_MAX];
+
+ if (!(dir = opendir(pfx)))
+ return NULL;
+
+ while ((de = readdir(dir))) {
+ if (de->d_name[0] != '.') {
+ FILE *f;
+ snprintf(fn, sizeof(fn), "%s/%s/%s", pfx, de->d_name, sfx);
+
+ if ((f = fopen(fn, m))) {
+ closedir(dir);
+ return f;
+ }
+
+ break;
+ }
+ }
+
+ closedir(dir);
+ return NULL;
+}
+
+gint get_temperature_value() {
+ char txt[256];
+ char*p;
+ int v, fd;
+ static FILE*f = NULL;
+ static gboolean old_acpi = FALSE;
+
+ if (!f) {
+ if (!(f = fopen_first("/proc/acpi/thermal_zone", "temperature", "r"))) {
+ if (!(f = fopen_first("/proc/acpi/thermal", "status", "r"))) {
+ failure("Unable to open ACPI temperature file.");
+ goto fail;
+ }
+
+ old_acpi = TRUE;
+ }
+ }
+
+ if (!(p = fgets(txt, sizeof(txt), f))) {
+ failure("Unable to read data from ACPI temperature file.");
+ goto fail;
+ }
+
+ fd = dup(fileno(f));
+ fclose(f);
+ f = fdopen(fd, "r");
+ g_assert(f);
+ fseek(f, 0, SEEK_SET);
+
+ if (!old_acpi) {
+ if (strlen(p) > 20)
+ v = atoi(p+20);
+ else
+ v = 0;
+ } else {
+ if (strlen(p) > 15)
+ v = atoi(p+15);
+ else
+ v = 0;
+ v=((v-2732)/10); /* convert from deciKelvin to degrees Celcius */
+ }
+
+ if (v > 100) v = 100;
+ if (v < 0) v = 0;
+
+ return v;
+
+fail:
+ if (f) {
+ fclose(f);
+ f = NULL;
+ }
+
+ return -1;
+}
+
+static MainWindow *mainWindow = NULL;
+
+int get_values() {
+ gint v1, v2;
+ static bool failed = false;
+
+ if (failed ||
+ (v1 = get_load_value()) < 0 ||
+ (v2 = get_temperature_value()) < 0)
+ goto fail;
+
+ load_meter.add_value(v1);
+ temperature_meter.add_value(v2);
+
+ if (mainWindow) {
+ mainWindow->update_values((guint) v1, (guint) v2);
+ mainWindow->refresh();
+ }
+
+ return 0;
+
+fail:
+ failed = true;
+ return -1;
+}
+
+bool timer_proc() {
+ if (get_values() < 0) {
+ Gtk::Main::quit();
+ return false;
+ }
+
+ return true;
+}
+
+int main(int argc, char *argv[]) {
+ Gtk::Main kit(argc, argv);
+
+ if (get_values() < 0)
+ return 1;
+
+ MainWindow window;
+ mainWindow = &window;
+ Glib::signal_timeout().connect(sigc::ptr_fun(&timer_proc), 1000);
+
+ kit.run(window);
+
+ return 0;
+}