Exemplo n.º 1
0
// NewFreeTree returns a new FreeTree using the data from a supplied SimpleTree.
func NewFreeTree(st *SimpleTree) (*FreeTree, error) {
	nbNodes := st.nodes
	nodeChunk, err := mmm.NewMemChunk(freeNode{}, nbNodes)
	if err != nil {
		return nil, err
	}
	dataChunk, err := mmm.NewMemChunk(st.root.data, nbNodes)
	if err != nil {
		return nil, err
	}

	ft := &FreeTree{nodeChunk: nodeChunk, dataChunk: dataChunk}
	for _, n := range st.flattenNodes() {
		node := (*freeNode)(unsafe.Pointer(ft.nodeChunk.Pointer(int(n.id))))
		node.id = n.id
		if n.left != nil {
			node.left = nodeChunk.Pointer(int(n.left.id))
		}
		if n.right != nil {
			node.right = nodeChunk.Pointer(int(n.right.id))
		}
		dataChunk.Write(int(n.id), n.data)

		if n == st.root {
			ft.root = node
		}
	}

	return ft, nil
}
Exemplo n.º 2
0
func main() {
	// create a new memory chunk that contains 3 Coordinate structures
	mc, err := mmm.NewMemChunk(Coordinate{}, 3)
	if err != nil {
		log.Fatal(err)
	}

	// print 3
	fmt.Println(mc.NbObjects())

	// write {3,9} at index 0, then print {3,9}
	fmt.Println(mc.Write(0, Coordinate{3, 9}))
	// write {17,2} at index 1, then print {17,2}
	fmt.Println(mc.Write(1, Coordinate{17, 2}))
	// write {42,42} at index 2, then print {42,42}
	fmt.Println(mc.Write(2, Coordinate{42, 42}))

	// print {17,2}
	fmt.Println(mc.Read(1))
	// print {42,42}
	fmt.Println(*((*Coordinate)(unsafe.Pointer(mc.Pointer(2)))))

	// free memory chunk
	if err := mc.Delete(); err != nil {
		log.Fatal(err)
	}
}
Exemplo n.º 3
0
func main() {

	/////////////////////////////////////////////////
	// A: Managed heap, 10 million pointers to int //
	/////////////////////////////////////////////////
	fmt.Println(`Case A: what happens when we store 10 million pointers to integer
on the managed heap?` + "\n")

	// build 10 million pointers to integer on the managed heap
	ints := make([]*int, 10*1e6)
	// init our pointers
	for i := range ints {
		j := i
		ints[i] = &j
	}

	// get rid of init garbage
	runtime.GC()
	debug.FreeOSMemory()

	for i := 0; i < 5; i++ {
		// randomly print one of our integers to make sure it's all working
		// as expected, and to prevent them from being optimized away
		fmt.Printf("\tvalue @ index %d: %d\n", i*1e4, *(ints[i*1e4]))

		// run GC
		now := time.Now().UnixNano()
		runtime.GC()
		fmt.Printf("\tGC time (managed heap, 10 million pointers): %d us\n", (time.Now().UnixNano()-now)/1e3)
	}

	// Results:
	//   value @ index 0: 0
	//   GC time (managed heap, 10 million pointers): 329840 us
	//   value @ index 10000: 10000
	//   GC time (managed heap, 10 million pointers): 325375 us
	//   value @ index 20000: 20000
	//   GC time (managed heap, 10 million pointers): 323367 us
	//   value @ index 30000: 30000
	//   GC time (managed heap, 10 million pointers): 327905 us
	//   value @ index 40000: 40000
	//   GC time (managed heap, 10 million pointers): 326469 us

	fmt.Println()

	//////////////////////////////////////////////////////
	// B: Unmanaged heap, pointers generated on-the-fly //
	//////////////////////////////////////////////////////
	fmt.Println(`Case B: mmm doesn't store any pointer, it doesn't need to.
Since the data is stored on an unmanaged heap, it cannot be collected
even if there's no reference to it. This allows mmm to generate
pointers only when something's actually reading or writing to the data.` + "\n")

	// build 10 million integers on an unmanaged heap
	intz, err := mmm.NewMemChunk(int(0), 10*1e6)
	if err != nil {
		log.Fatal(err)
	}
	// init our integers
	for i := 0; i < int(intz.NbObjects()); i++ {
		intz.Write(i, i)
	}

	// get rid of (almost all) previous garbage
	ints = nil
	runtime.GC()
	debug.FreeOSMemory()

	for i := 0; i < 5; i++ {
		// randomly print one of our integers to make sure it's all working
		// as expected (pointer to data is generated on-the-fly)
		fmt.Printf("\tvalue @ index %d: %d\n", i*1e4, intz.Read(i*1e4))

		// run GC
		now := time.Now().UnixNano()
		runtime.GC()
		fmt.Printf("\tGC time (unmanaged heap, pointers generated on-the-fly): %d us\n", (time.Now().UnixNano()-now)/1e3)
	}

	// Results:
	//   value @ index 0: 0
	//   GC time (unmanaged heap, pointers generated on-the-fly): 999 us
	//   value @ index 10000: 10000
	//   GC time (unmanaged heap, pointers generated on-the-fly): 665 us
	//   value @ index 20000: 20000
	//   GC time (unmanaged heap, pointers generated on-the-fly): 827 us
	//   value @ index 30000: 30000
	//   GC time (unmanaged heap, pointers generated on-the-fly): 882 us
	//   value @ index 40000: 40000
	//   GC time (unmanaged heap, pointers generated on-the-fly): 1016 us

	fmt.Println()

	///////////////////////////////////////////////////////
	// C: Unmanaged heap, storing all generated pointers //
	///////////////////////////////////////////////////////
	fmt.Println("Case C: what happens when we build and store 10 million pointers for each and every integer in our unmanaged memory chunk?\n")

	// build 10 million unsafe pointers on the managed heap
	ptrs := make([]unsafe.Pointer, 10*1e6)
	// init those pointers so that they point to the unmanaged heap
	for i := range ptrs {
		ptrs[i] = unsafe.Pointer(intz.Pointer(i))
	}

	// get rid of (almost all) previous garbage
	runtime.GC()
	debug.FreeOSMemory()

	for i := 0; i < 5; i++ {
		// randomly print one of our integers to make sure it's all working
		// as expected
		fmt.Printf("\tvalue @ index %d: %d\n", i*1e4, *(*int)(ptrs[i*1e4]))

		// run GC
		now := time.Now().UnixNano()
		runtime.GC()
		fmt.Printf("\tGC time (unmanaged heap, all generated pointers stored): %d us\n", (time.Now().UnixNano()-now)/1e3)
	}

	// Results:
	//   value @ index 0: 0
	//   GC time (unmanaged heap, all generated pointers stored): 47196 us
	//   value @ index 10000: 10000
	//   GC time (unmanaged heap, all generated pointers stored): 47307 us
	//   value @ index 20000: 20000
	//   GC time (unmanaged heap, all generated pointers stored): 47485 us
	//   value @ index 30000: 30000
	//   GC time (unmanaged heap, all generated pointers stored): 47145 us
	//   value @ index 40000: 40000
	//   GC time (unmanaged heap, all generated pointers stored): 47221 us

	fmt.Println()

	///////////////////////////////////////////////////
	// D: Unmanaged heap, storing numeric references //
	///////////////////////////////////////////////////
	fmt.Println(`Case D: as case C showed, storing all the generated unsafe pointers to the unmanaged heap is still order of magnitudes faster than storing safe pointers to the managed heap.
Still, why keep pointer values when our data is not garbage-collectable?
What happens if we store all the generated pointers as numeric references?` + "\n")

	// build 10 million numeric references on the managed heap
	refs := make([]uintptr, 10*1e6)
	// init those references so that they each contain one of the addresses in
	// our unmanaged heap
	for i := range refs {
		refs[i] = uintptr(ptrs[i])
	}

	// get rid of (almost all) previous garbage
	ptrs = nil
	runtime.GC()
	debug.FreeOSMemory()

	for i := 0; i < 5; i++ {
		// randomly print one of our integers to make sure it's all working
		// as expected
		fmt.Printf("\tvalue @ index %d: %d\n", i*1e4, *(*int)(unsafe.Pointer(refs[i*1e4])))

		// run GC
		now := time.Now().UnixNano()
		runtime.GC()
		fmt.Printf("\tGC time (unmanaged heap, all numeric references stored): %d us\n", (time.Now().UnixNano()-now)/1e3)
	}

	// Results:
	//   value @ index 0: 0
	//   GC time (unmanaged heap, all numeric references stored): 715 us
	//   value @ index 10000: 10000
	//   GC time (unmanaged heap, all numeric references stored): 783 us
	//   value @ index 20000: 20000
	//   GC time (unmanaged heap, all numeric references stored): 882 us
	//   value @ index 30000: 30000
	//   GC time (unmanaged heap, all numeric references stored): 711 us
	//   value @ index 40000: 40000
	//   GC time (unmanaged heap, all numeric references stored): 723 us
}