[Piglit] [PATCH] Added a simple logging class. Updated Test::doRun to use the new log.

Chad Versace chad at chad-versace.us
Thu Jan 20 11:01:15 PST 2011


The patch looks good to me.


On 01/20/2011 09:30 AM, Ian Romanick wrote:
> On 01/19/2011 05:25 PM, U. Artie Eoff wrote:
>> Added log.py which includes a simple Logger class that wraps some
>> basic functions from the Python logging module. The log wrapper
>> simplifies setup and will accommodate thread synchronization in the
>> future.  Test::doRun now uses the new log facility.
>> NOTE: this changes the format of the 'test progress' previously
>> printed via stdout.
> 
>> Added patterns.py which includes a Singleton class design pattern
>> to support the Logger class.  Future design patterns can be added
>> to this file.
> 
>> Tested with Python 2.7 on Linux.  All should be compatible with
>> Windows and Mac and most earlier widely-used versions of Python.
> 
> I like the change.  I want some comment from non-Intel people before I
> push this change.  Part of the reason for the change in output format is
> that Artie's next change set is going to make CPU-only tests (e.g., all
> of the parser tests) and GPU tests run concurrently.  Without this
> change to the logging, you'd see things like:
> 
> Test: some_test
> Test: some_other_test
>     result: skip
>     result: fail
> 
> That seems bad.  Which test failed and which test was skipped?
> 
> I'd like to hear
> 
> a) People don't hate the change.
> 
> b) The change works on Mac and Windows.
> 
>> ---
>>  framework/core.py     |   12 ++++--
>>  framework/log.py      |   46 ++++++++++++++++++++++++++
>>  framework/patterns.py |   87 +++++++++++++++++++++++++++++++++++++++++++++++++
>>  3 files changed, 141 insertions(+), 4 deletions(-)
>>  create mode 100644 framework/log.py
>>  create mode 100644 framework/patterns.py
> 
>> diff --git a/framework/core.py b/framework/core.py
>> index b975cb3..8d98f70 100644
>> --- a/framework/core.py
>> +++ b/framework/core.py
>> @@ -31,6 +31,7 @@ import subprocess
>>  import sys
>>  import time
>>  import traceback
>> +from log import log
>>  from cStringIO import StringIO
> 
>>  __all__ = [
>> @@ -304,10 +305,14 @@ class Test:
>>  		if len(env.exclude_filter) > 0:
>>  			if True in map(lambda f: f.search(path) != None, env.exclude_filter):
>>  				return None
>> +
>> +		def status(msg):
>> +			log(msg = msg, channel = path)
>> +
>>  		# Run the test
>>  		if env.execute:
>>  			try:
>> -				print "Test: %(path)s" % locals()
>> +				status("running")
>>  				time_start = time.time()
>>  				result = self.run()
>>  				time_end = time.time()
>> @@ -325,9 +330,8 @@ class Test:
>>  				result['exception'] = str(sys.exc_info()[0]) + str(sys.exc_info()[1])
>>  				result['traceback'] = '@@@' + "".join(traceback.format_tb(sys.exc_info()[2]))
> 
>> -			if result['result'] != 'pass':
>> -				print "    result: %(result)s" % { 'result': result['result'] }
>> -
>> +			status(result['result'])
>> +			
>>  			result.write(env.file, path)
>>  			if Test.sleep:
>>  				time.sleep(Test.sleep)
>> diff --git a/framework/log.py b/framework/log.py
>> new file mode 100644
>> index 0000000..c3fbdd7
>> --- /dev/null
>> +++ b/framework/log.py
>> @@ -0,0 +1,46 @@
>> +#
>> +# Copyright (c) 2010 Intel Corporation
>> +#
>> +# Permission is hereby granted, free of charge, to any person obtaining a
>> +# copy of this software and associated documentation files (the "Software"),
>> +# to deal in the Software without restriction, including without limitation
>> +# the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> +# and/or sell copies of the Software, and to permit persons to whom the
>> +# Software is furnished to do so, subject to the following conditions:
>> +#
>> +# The above copyright notice and this permission notice (including the next
>> +# paragraph) shall be included in all copies or substantial portions of the
>> +# Software.
>> +#
>> +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> +# IN THE SOFTWARE.
>> +#
>> +
>> +from patterns import Singleton
>> +import logging
>> +
>> +class Logger(Singleton):
>> +	def __logMessage(self, logfunc, message, **kwargs):
>> +		[logfunc(line, **kwargs) for line in message.split('\n')]
>> +
>> +	def getLogger(self, channel = None):
>> +		if 0 == len(logging.root.handlers):
>> +			logging.basicConfig(
>> +				format = "[%(asctime)s] :: %(message)+8s :: %(name)s",
>> +				datefmt = "%c",
>> +				level = logging.INFO,
>> +			)
>> +		if channel is None:
>> +			channel = "base"
>> +		logger = logging.getLogger(channel)
>> +		return logger
>> +
>> +	def log(self, type = logging.INFO, msg = "", channel = None):
>> +		self.__logMessage(lambda m, **kwargs: self.getLogger(channel).log(type, m, **kwargs), msg)
>> +
>> +log = Logger().log
>> diff --git a/framework/patterns.py b/framework/patterns.py
>> new file mode 100644
>> index 0000000..3d7f22b
>> --- /dev/null
>> +++ b/framework/patterns.py
>> @@ -0,0 +1,87 @@
>> +#
>> +# Copyright (c) 2010 Intel Corporation
>> +#
>> +# Permission is hereby granted, free of charge, to any person obtaining a
>> +# copy of this software and associated documentation files (the "Software"),
>> +# to deal in the Software without restriction, including without limitation
>> +# the rights to use, copy, modify, merge, publish, distribute, sublicense,
>> +# and/or sell copies of the Software, and to permit persons to whom the
>> +# Software is furnished to do so, subject to the following conditions:
>> +#
>> +# The above copyright notice and this permission notice (including the next
>> +# paragraph) shall be included in all copies or substantial portions of the
>> +# Software.
>> +#
>> +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
>> +# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
>> +# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
>> +# THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
>> +# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
>> +# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
>> +# IN THE SOFTWARE.
>> +#
>> +
>> +import threading
>> +
>> +class Singleton(object):
>> +	'''
>> +		Modeled after http://www.python.org/download/releases/2.2.3/descrintro/*__new__
>> +
>> +		A thread-safe (mostly -- see NOTE) Singleton class pattern.
>> +
>> +		NOTE: deleting a singleton instance (i.e. Singleton::delInstance) does not guarantee that something
>> +		else is currently using it. To reduce this risk, a program should not hold a reference to the
>                      ^^^^^^^^^^^^
> I think that should be "is not currently".  I can change that when I
> push the patch.
> 
>> +		instance.  Rather, use the create/construct syntax (see example below) to access the instance.  Yet,
>> +		this still does not guarantee that this type of usage will result in a desired effect in a
>> +		multithreaded program.
>> +		You've been warned so use the singleton pattern wisely!
>> +
>> +		Example:
>> +		
>> +		class MySingletonClass(Singleton):
>> +			def init(self):
>> +				print "in MySingletonClass::init()", self
>> +
>> +			def foo(self):
>> +				print "in MySingletonClass::foo()", self
>> +
>> +		MySingletonClass().foo()
>> +		MySingletonClass().foo()
>> +		MySingletonClass().foo()
>> +
>> +		---> output will look something like this:
>> +		in MySingletonClass::init() <__main__.MySingletonClass object at 0x7ff5b322f3d0>
>> +		in MySingletonClass::foo() <__main__.MySingletonClass object at 0x7ff5b322f3d0>
>> +		in MySingletonClass::foo() <__main__.MySingletonClass object at 0x7ff5b322f3d0>
>> +		in MySingletonClass::foo() <__main__.MySingletonClass object at 0x7ff5b322f3d0>
>> +	'''
>> +
>> +	lock = threading.RLock()
>> +
>> +	def __new__(cls, *args, **kwargs):
>> +		try:
>> +			cls.lock.acquire()
>> +			it = cls.__dict__.get('__it__')
>> +			if it is not None:
>> +				return it
>> +			cls.__it__ = it = object.__new__(cls)
>> +			it.init(*args, **kwargs)
>> +			return it
>> +		finally: # this always gets called, even when returning from within the try block
>> +			cls.lock.release()
>> +
>> +	def init(self, *args, **kwargs):
>> +		'''
>> +			Derived classes should override this method to do its initializations
>> +			The derived class should not implement a '__init__' method.
>> +		'''
>> +		pass
>> +
>> +	@classmethod
>> +	def delInstance(cls):
>> +		cls.lock.acquire()
>> +		try:
>> +			if cls.__dict__.get('__it__') is not None:
>> +				del cls.__it__
>> +		finally:
>> +			cls.lock.release()
_______________________________________________
Piglit mailing list
Piglit at lists.freedesktop.org
http://lists.freedesktop.org/mailman/listinfo/piglit

-- 
Chad Versace
chad.versace at intel.com
chad at chad-versace.us


More information about the Piglit mailing list