1 /*
2 This file is part of MADNESS.
3
4 Copyright (C) 2007,2010 Oak Ridge National Laboratory
5
6 This program is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program; if not, write to the Free Software
18 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
20 For more information please contact:
21
22 Robert J. Harrison
23 Oak Ridge National Laboratory
24 One Bethel Valley Road
25 P.O. Box 2008, MS-6367
26
27 email: harrisonrj@ornl.gov
28 tel: 865-241-3937
29 fax: 865-572-0680
30
31
32 $Id: world.cc 454 2008-01-26 03:08:15Z rjharrison $
33 */
34
35 #include <madness/world/worldmem.h>
36 #include <cstdlib>
37 //#include <cstdio>
38 #include <climits>
39 #include <iostream>
40 #include <iomanip>
41
42 /*
43
44 Memory allocation structure
45
46 ---------
47 base <--- actual-pointer
48 ...
49 user-size <--- p - sizeof(3*long)
50 actual-pointer <--- p - sizeof(2*long)
51 pre-checksum <--- p - sizeof(long)
52 ---------
53 user-size bytes <--- p
54 16-byte aligned
55 ---------
56 post-checksum
57 ---------
58
59 */
60
61
62 static madness::WorldMemInfo stats = {0, 0, 0, 0, 0, 0, ULONG_MAX, false};
63
64 namespace madness {
world_mem_info()65 WorldMemInfo* world_mem_info() {
66 return &stats;
67 }
68
do_new(void * p,std::size_t size)69 void WorldMemInfo::do_new(void *p, std::size_t size) {
70 ++num_new_calls;
71 ++cur_num_frags;
72 if (cur_num_frags > max_num_frags) max_num_frags = cur_num_frags;
73 cur_num_bytes += size;
74 if (cur_num_bytes > max_num_bytes) max_num_bytes = cur_num_bytes;
75
76 if (trace)
77 std::cout << "WorldMemInfo: allocating " << p << " " << size << "\n";
78 }
79
do_del(void * p,std::size_t size)80 void WorldMemInfo::do_del(void *p, std::size_t size) {
81 ++num_del_calls;
82 --cur_num_frags;
83 cur_num_bytes -= size;
84
85 if (trace)
86 std::cout << "WorldMemInfo: deleting " << p << " " << size << "\n";
87 }
88
print() const89 void WorldMemInfo::print() const {
90 std::cout.flush();
91 std::cout << "\n MADNESS memory statistics\n";
92 std::cout << " -------------------------\n";
93 std::cout << " overhead bytes per frag " << std::setw(12)
94 << overhead << "\n";
95 std::cout << " calls to new and del " << std::setw(12)
96 << num_new_calls << " " << std::setw(12) << num_del_calls << "\n";
97 std::cout << " cur and max frags allocated " << std::setw(12)
98 << cur_num_frags << " " << std::setw(12) << max_num_frags << "\n";
99 std::cout << " cur and max bytes allocated " << std::setw(12)
100 << cur_num_bytes << " " << std::setw(12) << max_num_bytes << "\n";
101 }
102
reset()103 void WorldMemInfo::reset() {
104 num_new_calls = 0;
105 num_del_calls = 0;
106 cur_num_frags = 0;
107 max_num_frags = 0;
108 cur_num_bytes = 0;
109 max_num_bytes = 0;
110 }
111
112 } // namespace madness
113
114 #ifdef WORLD_GATHER_MEM_STATS
115
116 #include <exception>
117
118 static const unsigned long pre_checksum = 0xdeadbeef;
119 static const unsigned char post_checksum = 0xab;
120
121 namespace madness {
122 // This is called from the delete operator when a buffer underflow is detected.
123 // Any error code for this condition should be added here.
world_mem_buffer_underflow()124 void world_mem_buffer_underflow() {
125 std::cerr << "WorldMemInfo: Buffer underflow detected.\n" <<
126 "Set a breakpoint at madness::world_mem_buffer_underflow() to debug.\n";
127 }
128
129 // This is called from the delete operator when a buffer overflow is detected.
130 // Any error code for this condition should be added here.
world_mem_buffer_overflow()131 void world_mem_buffer_overflow() {
132 std::cerr << "WorldMemInfo: Buffer overflow detected.\n" <<
133 "Set a breakpoint at madness::world_mem_buffer_overflow() to debug.\n";
134 }
135 } // namespace madness
136
operator new(size_t size)137 void* operator new(size_t size) throw (std::bad_alloc) {
138 // user-size + actual_pointer + pre_checksum + post_checksum + padding
139 std::size_t actual_size = size + madness::WorldMemInfo::overhead;
140
141 if (size+stats.cur_num_bytes > stats.max_mem_limit)
142 throw std::bad_alloc(); //MADNESS_EXCEPTION("WorldMemInfo: execeeded max_mem_limit", stats.max_mem_limit);
143
144 unsigned long* actual_pointer= (unsigned long*) malloc(actual_size);
145 if (actual_pointer==0) throw std::bad_alloc(); // ANSI/ISO compliant behavior
146 unsigned char* p = (unsigned char*)(actual_pointer + 3);
147
148 p += 16 - (((unsigned long) p)&0x0f);
149 p[size] = post_checksum;
150
151 unsigned long* lp = (unsigned long*) p; // Non-portable alignment assumption here????
152
153 lp[-1] = pre_checksum;
154 lp[-2] = (unsigned long) actual_pointer;
155 lp[-3] = size;
156
157 stats.do_new(p, size);
158
159 return (void *) p;
160 }
161
operator delete(void * p)162 void operator delete(void *p) throw() {
163 unsigned long* lp = (unsigned long*) p;
164 if (lp[-1] != pre_checksum) madness::world_mem_buffer_underflow();
165 unsigned long* actual_pointer = (unsigned long*) lp[-2];
166 std::size_t size = lp[-3];
167 unsigned char* cp = (unsigned char*) p;
168 if (cp[size] != post_checksum) madness::world_mem_buffer_overflow();
169
170 stats.do_del(p, size);
171
172 free(actual_pointer);
173 }
174
175 #endif // defined(WORLD_GATHER_MEM_STATS)
176
177 namespace madness {
178 namespace detail {
Vm_cstr()179 template <> const char* Vm_cstr<char>() { return "Vm"; }
Vm_cstr()180 template <> const wchar_t* Vm_cstr<wchar_t>() { return L"Vm"; }
181 } // namespace detail
182 } // namespace madness
183
184