2 * Copyright (c) 2001 The Anthill Team
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License version 2 as
6 * published by the Free Software Foundation.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU Lesser General Public License for more details.
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this program; if not, write to the Free Software
15 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 package peersim.edsim;
21 import peersim.core.Node;
22 import peersim.core.CommonState;
23 import peersim.config.Configuration;
24 import peersim.config.IllegalParameterException;
27 * The Heap data structure used to maintain events "sorted" by
28 * scheduled time and to obtain the next event to be executed.
30 * @author Alberto Montresor
31 * @version $Revision: 1.10 $
33 public class Heap implements PriorityQ {
35 //--------------------------------------------------------------------------
37 //--------------------------------------------------------------------------
40 * This parameter specifies how many
41 * bits are used to order events that occur at the same time. Defaults
42 * to 8. A value smaller than 8 causes an IllegalParameterException.
43 * Higher values allow for a better discrimination, but reduce
44 * the maximal time steps that can be simulated.
47 private static final String PAR_PBITS = "pbits";
48 private static final String PAR_PBITS_LEGACY = "simulation.timebits";
51 * Specifies the initial capacity of the heap. Defaults to 65536.
54 private static final String PAR_SIZE = "size";
57 //--------------------------------------------------------------------------
59 //--------------------------------------------------------------------------
61 // The following arrays are four heaps ordered by time. The alternative
62 // approach (i.e. to store event objects) requires much more memory,
63 // and based on some tests that I've done is not really much faster.
65 /** Event component of the heap */
66 private Object[] events;
68 /** Time component of the heap */
71 /** Node component of the heap */
74 /** Pid component of the heap */
77 /** Number of elements */
80 /** Singleton event object used to return (event, time, node, pid) tuples */
81 private final Event ev = new Event();
83 /** The number of bits reserved to order event with the same timestamp */
84 private final int pbits;
86 /** The mask to test whether the time value fits into the range we can
88 private final long overflowMask;
90 //--------------------------------------------------------------------------
92 //--------------------------------------------------------------------------
95 * Initializes a new heap using defaults.
98 this(""); // "" is not a valid prefix for a component
101 //--------------------------------------------------------------------------
104 * Initializes a new heap using the configuration.
106 public Heap(String prefix) {
108 int size = Configuration.getInt(prefix+"."+PAR_SIZE,65536);
110 // some complex stuff to deal with legacy parameter names...
111 if( !Configuration.contains(PAR_PBITS_LEGACY) )
112 pbits = Configuration.getInt(prefix+"."+PAR_PBITS,8);
115 pbits = Configuration.getInt(PAR_PBITS_LEGACY);
116 if( Configuration.contains(prefix+"."+PAR_PBITS) )
117 throw new IllegalParameterException(PAR_PBITS_LEGACY,
118 "Your configuration file contains both "+
119 prefix+"."+PAR_PBITS+ " and "+
120 PAR_PBITS_LEGACY+"; please remove "+
124 if (pbits < 8 || pbits >= 31) {
125 throw new IllegalParameterException(prefix+"."+PAR_PBITS,
126 "This parameter should be >= 8 or < 31");
128 overflowMask = ~maxTime();
129 events = new Object[size];
130 times = new long[size];
131 nodes = new Node[size];
132 pids = new byte[size];
135 //--------------------------------------------------------------------------
137 //--------------------------------------------------------------------------
140 * Returns the current number of events in the system.
147 //--------------------------------------------------------------------------
150 * Add a new event, to be scheduled at the specified time.
152 * @param time the time at which this event should be scheduled
153 * @param event the object describing the event
154 * @param node the node at which the event has to be delivered
155 * @param pid the protocol that handles the event
157 public void add(long time, Object event, Node node, byte pid)
159 add(time,event,node,pid,CommonState.r.nextInt(1 << pbits));
162 //--------------------------------------------------------------------------
165 * Add a new event, to be scheduled at the specified time.
167 * @param time the time at which this event should be scheduled
168 * @param event the object describing the event
169 * @param node the node at which the event has to be delivered
170 * @param pid the protocol that handles the event
172 public void add(long time, Object event, Node node, byte pid, long priority)
174 if( (time&overflowMask) != 0 ) throw new
175 IllegalArgumentException("Time overflow: time="+time);
176 //XXX should we test priority overflow? How much does it cost?
178 time = (time << pbits) | priority;
182 put(pos, time, event, node, pid);
183 while (pos > 1 && getTime(pos / 2) > time) {
189 //--------------------------------------------------------------------------
192 * Removes the first event in the heap and returns it.
193 * Note that, to avoid garbage collection, a singleton instance of
194 * the Event class is used. This means that data contained in the
195 * returned event are overwritten when a new invocation of this
196 * method is performed.
197 * @return first event or null if size is zero
199 public Event removeFirst() {
201 if(size==0) return null;
203 ev.time = times[0] >> pbits;
204 ev.event = events[0];
213 //--------------------------------------------------------------------------
215 public long maxTime() { return Long.MAX_VALUE >> pbits; }
217 //--------------------------------------------------------------------------
219 public long maxPriority() { return (1L << pbits)-1; }
221 //--------------------------------------------------------------------------
224 * Prints the time values contained in the heap.
226 public String toString()
228 StringBuffer buffer = new StringBuffer();
229 buffer.append("[Size: " + size + " Times: ");
230 for (int i=1; i <= size; i++) {
231 buffer.append(getTime(i)+",");
234 return buffer.toString();
238 //--------------------------------------------------------------------------
240 //--------------------------------------------------------------------------
245 private void minHeapify(int index)
247 // The time to be placed of the current node
248 long time = getTime(index);
249 // Left, right children of the current index
251 // Their associated time
253 // The minimum time between val, lt, rt
255 // The index of the mininum time
256 int minindex = index;
262 if (l <= size && (lt = getTime(l)) < mintime) {
266 if (r <= size && (rt = getTime(r)) < mintime) {
270 if (minindex != index) {
271 swap(minindex, index);
273 } while (minindex != index);
276 //--------------------------------------------------------------------------
281 private void swap(int i1, int i2) {
286 Object te = events[i1];
287 events[i1] = events[i2];
291 times[i1] = times[i2];
295 nodes[i1] = nodes[i2];
303 //--------------------------------------------------------------------------
308 private long getTime(int index) {
309 /* Compute first and second index, and return the value */
314 //--------------------------------------------------------------------------
319 private void put(int index, long time, Object event, Node node, byte pid) {
322 if (index >= events.length) {
325 events[index] = event;
331 //--------------------------------------------------------------------------
336 private void doubleCapacity() {
337 int oldsize = events.length;
338 int newsize = oldsize*2;
339 Object[] te = new Object[newsize];
340 System.arraycopy(events, 0, te, 0, oldsize);
342 long[] tt = new long[newsize];
343 System.arraycopy(times, 0, tt, 0, oldsize);
345 Node[] tn = new Node[newsize];
346 System.arraycopy(nodes, 0, tn, 0, oldsize);
348 byte[] tp = new byte[newsize];
349 System.arraycopy(pids, 0, tp, 0, oldsize);
353 //--------------------------------------------------------------------------
355 //--------------------------------------------------------------------------
358 public static void main(String[] args) {
359 Random random = new Random();
360 Heap heap = new Heap();
362 if( args.length > 0 ) rep = Integer.parseInt(args[0]);
363 int[] values1 = new int[rep];
364 long[] values2 = new long[rep];
365 for (int i = 0; i < rep; i++) {
366 values1[i] = random.nextInt(1000000000);
369 long time1 = System.currentTimeMillis();
370 for (int i = 0; i < rep; i++) {
371 heap.add(values1[i], null, null, (byte) 1);
373 long time2 = System.currentTimeMillis();
374 System.out.println("Inserting: " + (time2-time1));
376 time1 = System.currentTimeMillis();
377 for (int i = 0; i < rep; i++) {
378 values2[i] = heap.removeFirst().time;
380 time2 = System.currentTimeMillis();
381 System.out.println("Removing: " + (time2-time1));
383 Arrays.sort(values1);
384 for (int i=0; i<rep; i++) {
385 if (values1[i] != values2[i])
386 System.out.print("+");