#!/usr/bin/env python
"""
Test python-maelie
"""
# <http://jam-bazaar.blogspot.de/2009/11/memory-debugging-with-meliae.html>
# <file:../BUG.DONE/35977_testlibcloud.py>

from sys import argv, exit, stderr
from threading import Thread
from time import sleep
from meliae import scanner, loader
from os import listdir, fork, wait
# from gzip import GzipFile
from collections import defaultdict
from gc import collect
from locale import setlocale, LC_ALL

DELAY = 2
SUFFIX = '.json'


def dump_inprocess(index):
	filename = '%d%s' % (index, SUFFIX)
	with open(filename, 'wb') as output:
		# gzip = GzipFile(mode='wb', compresslevel=9, fileobj=output)
		scanner.dump_all_objects(output)


def dump_fork(index):
	pid = fork()
	if pid == 0:
		dump_inprocess(index)
		exit(0)
	wait()


def main():
	setlocale(LC_ALL, '')
	try:
		mode = argv[1]
		if mode == 'd':
			dummy(dump_inprocess)
		elif mode == 'f':
			dummy(dump_fork)
		elif mode == 'a':
			analyze()
		elif mode == 'c':
			compare(argv[2], argv[3])
		else:
			usage(1)
	except IndexError:
		usage(2)


def dummy(dump):
	dump(0)
	SIZES = (1000000, 2000000)
	threads = [Thread(target=alloc, args=(size,)) for size in SIZES]
	dump(1)
	for thread in threads:
		thread.start()
	del thread
	dump(2)
	sleep(DELAY / 2)
	dump(3)
	for thread in threads:
		thread.join()
	del thread
	dump(4)
	del threads
	dump(5)
	collect()
	dump(6)


def alloc(size):
	data = [None] * size
	sleep(DELAY)
	del data


def analyze():
	files = [(int(_[:-len(SUFFIX)]), _) for _ in listdir('.') if _.endswith(SUFFIX)]
	prev_sum = {}
	for index, filename in sorted(files):
		sm = load(filename)
		# with open('%d.summary' % (index,), 'w') as output:
		# 	print >> output, sm

		diff(prev_sum, sm.type_summaries)
		prev_sum = sm.type_summaries

		print


def compare(old_filename, new_filename):
	old = load(old_filename)
	new = load(new_filename)
	diff(old.type_summaries, new.type_summaries)


def load(filename):
	print filename
	om = loader.load(filename, show_prog=False, collapse=True)
	om.remove_expensive_references()
	om.compute_parents()
	# om.collapse_instance_dicts()
	sm = om.summarize()
	return sm


def diff(old, new):
	comp = defaultdict(lambda: [None, None])
	for typ, usage in old.items():
		comp[typ][0] = usage
	for typ, usage in new.items():
		comp[typ][1] = usage
	del old, new, usage

	ZERO = (0, 0, 0)
	for typ, (old, new) in comp.items():
		data = map(sum, zip(
			(-old.count, -old.total_size, -old.max_size) if old else ZERO,
			(new.count, new.total_size, new.max_size) if new else ZERO,
		))
		if any(data):
			sign = '+' if not old else '-' if not new else '!'
			print '{sign} {typ:_<30} {data[0]:_>+12n} {data[1]:_>+12n} {data[2]:_>+12n}'.format(**locals())


def usage(ret):
	print >> stderr, 'Usage: %s <d|f|a|c> ...' % (argv[0],)
	exit(ret)


if __name__ == '__main__':
	main()
