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