1 /**
2 * \brief Memory statistics dialog
3 *
4 * Authors:
5 * MenTaLguY <mental@rydia.net>
6 *
7 * Copyright (C) 2005
8 *
9 * Released under GNU GPL. Read the file 'COPYING' for more information.
10 */
12 #ifdef HAVE_CONFIG_H
13 # include <config.h>
14 #endif
16 #include <glibmm/i18n.h>
17 #include <gtkmm/liststore.h>
18 #include <gtkmm/treeview.h>
20 #include "gc-core.h"
21 #include "ui/dialog/memory.h"
22 #include "debug/heap.h"
23 #include "verbs.h"
25 namespace Inkscape {
26 namespace UI {
27 namespace Dialog {
29 namespace {
31 Glib::ustring format_size(std::size_t value) {
32 if (!value) {
33 return Glib::ustring("0");
34 }
36 typedef std::vector<char> Digits;
37 typedef std::vector<Digits *> Groups;
39 Groups groups;
41 Digits *digits;
43 while (value) {
44 unsigned places=3;
45 digits = new Digits();
46 digits->reserve(places);
48 while ( value && places ) {
49 digits->push_back('0' + (char)( value % 10 ));
50 value /= 10;
51 --places;
52 }
54 groups.push_back(digits);
55 }
57 Glib::ustring temp;
59 while (true) {
60 digits = groups.back();
61 while (!digits->empty()) {
62 temp.append(1, digits->back());
63 digits->pop_back();
64 }
65 delete digits;
67 groups.pop_back();
68 if (groups.empty()) {
69 break;
70 }
72 temp.append(",");
73 }
75 return temp;
76 }
78 }
80 struct Memory::Private {
81 class ModelColumns : public Gtk::TreeModel::ColumnRecord {
82 public:
83 Gtk::TreeModelColumn<Glib::ustring> name;
84 Gtk::TreeModelColumn<Glib::ustring> used;
85 Gtk::TreeModelColumn<Glib::ustring> slack;
86 Gtk::TreeModelColumn<Glib::ustring> total;
88 ModelColumns() { add(name); add(used); add(slack); add(total); }
89 };
91 Private() {
92 model = Gtk::ListStore::create(columns);
93 view.set_model(model);
94 view.append_column(_("Heap"), columns.name);
95 view.append_column(_("In Use"), columns.used);
96 // TRANSLATORS: "Slack" refers to memory which is in the heap but currently unused.
97 // More typical usage is to call this memory "free" rather than "slack".
98 view.append_column(_("Slack"), columns.slack);
99 view.append_column(_("Total"), columns.total);
100 }
102 void update();
104 void start_update_task();
105 void stop_update_task();
107 ModelColumns columns;
108 Glib::RefPtr<Gtk::ListStore> model;
109 Gtk::TreeView view;
111 sigc::connection update_task;
112 };
114 void Memory::Private::update() {
115 Debug::Heap::Stats total = { 0, 0 };
117 int aggregate_features = Debug::Heap::SIZE_AVAILABLE | Debug::Heap::USED_AVAILABLE;
118 Gtk::ListStore::iterator row;
120 row = model->children().begin();
122 for ( unsigned i = 0 ; i < Debug::heap_count() ; i++ ) {
123 Debug::Heap *heap=Debug::get_heap(i);
124 if (heap) {
125 Debug::Heap::Stats stats=heap->stats();
126 int features=heap->features();
128 aggregate_features &= features;
130 if ( row == model->children().end() ) {
131 row = model->append();
132 }
134 row->set_value(columns.name, Glib::ustring(heap->name()));
135 if ( features & Debug::Heap::SIZE_AVAILABLE ) {
136 row->set_value(columns.total, format_size(stats.size));
137 total.size += stats.size;
138 } else {
139 row->set_value(columns.total, Glib::ustring(_("Unknown")));
140 }
141 if ( features & Debug::Heap::USED_AVAILABLE ) {
142 row->set_value(columns.used, format_size(stats.bytes_used));
143 total.bytes_used += stats.bytes_used;
144 } else {
145 row->set_value(columns.used, Glib::ustring(_("Unknown")));
146 }
147 if ( features & Debug::Heap::SIZE_AVAILABLE &&
148 features & Debug::Heap::USED_AVAILABLE )
149 {
150 row->set_value(columns.slack, format_size(stats.size - stats.bytes_used));
151 } else {
152 row->set_value(columns.slack, Glib::ustring(_("Unknown")));
153 }
155 ++row;
156 }
157 }
159 if ( row == model->children().end() ) {
160 row = model->append();
161 }
163 Glib::ustring value;
165 row->set_value(columns.name, Glib::ustring(_("Combined")));
167 if ( aggregate_features & Debug::Heap::SIZE_AVAILABLE ) {
168 row->set_value(columns.total, format_size(total.size));
169 } else {
170 row->set_value(columns.total, Glib::ustring("> ") + format_size(total.size));
171 }
173 if ( aggregate_features & Debug::Heap::USED_AVAILABLE ) {
174 row->set_value(columns.used, format_size(total.bytes_used));
175 } else {
176 row->set_value(columns.used, Glib::ustring("> ") + format_size(total.bytes_used));
177 }
179 if ( aggregate_features & Debug::Heap::SIZE_AVAILABLE &&
180 aggregate_features & Debug::Heap::USED_AVAILABLE )
181 {
182 row->set_value(columns.slack, format_size(total.size - total.bytes_used));
183 } else {
184 row->set_value(columns.slack, Glib::ustring(_("Unknown")));
185 }
187 ++row;
189 while ( row != model->children().end() ) {
190 row = model->erase(row);
191 }
192 }
194 void Memory::Private::start_update_task() {
195 update_task.disconnect();
196 update_task = Glib::signal_timeout().connect(
197 sigc::bind_return(sigc::mem_fun(*this, &Private::update), true),
198 500
199 );
200 }
202 void Memory::Private::stop_update_task() {
203 update_task.disconnect();
204 }
206 Memory::Memory(Behavior::BehaviorFactory behavior_factory)
207 : Dialog (behavior_factory, "dialogs.memory", SP_VERB_HELP_MEMORY, _("Recalculate")),
208 _private(*(new Memory::Private()))
209 {
210 get_vbox()->add(_private.view);
212 _private.update();
214 show_all_children();
216 signal_show().connect(sigc::mem_fun(_private, &Private::start_update_task));
217 signal_hide().connect(sigc::mem_fun(_private, &Private::stop_update_task));
219 _private.start_update_task();
220 }
222 Memory::~Memory() {
223 delete &_private;
224 }
226 void Memory::_apply() {
227 GC::Core::gcollect();
228 _private.update();
229 }
231 } // namespace Dialog
232 } // namespace UI
233 } // namespace Inkscape
235 /*
236 Local Variables:
237 mode:c++
238 c-file-style:"stroustrup"
239 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
240 indent-tabs-mode:nil
241 fill-column:99
242 End:
243 */
244 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :