Exceptions Package -- Feature Log ================================================================== Enhancement 006: Rehink virtuallity of ZMexception Statement of suggested enhancement 12/10/01 ---------------------------------- version 2.0.5 S. Snyder notes that about 15K of code is generated per ZMthrow_ of a distinct ZMexception. He suggests that 85% of that might be eliminated by emasculating the virtuallity of the class -- his comment: ...by far the largest object module in this library (at 760k) is one that actually throws these exceptions. For each of the 48 exceptions, there's a function that constructs the error message and then calls ZMthrow_from with the appropriate instance. What takes up the bulk of the space in the object file (at about 13k/exception) are the virtual functions generated for each exception, plus the vtab and tid information. At some point, it may be worth thinking about whether we really need to define the full set of virtual functions for every exception. For example, it appears that i can remove all of the virtual functions except for classInfo() without changing the behavior for the cases that i actually end up using. A more code-size-efficient implementation (for the limit of many ZMexception subclasses) might make ZMexception non-virtual, and have all custom behavior driven through the classinfo object. (In this case, a ZMexception instance would have a pointer to its corresponding classinfo instance. This is the moral equivalent of a vtable pointer, but i think we end up with more code sharing this way.) - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Technical Information --------------------- I'm not confident that this can be done without potentially breaking other people's code which MAY take advatnage of the virtual methods. The code size gain is so large that it is probably worth looking into this, but we would have to come up with some SAFE way of doing it. The problem probably stems from the ZMexVirtualMethods(Parent,Class) macro: This is used for every definition of an exception type, and it defines 5 virtual methods, overriding those 5 in the base class. WB, MF and JBK look at this and agree that modifications to eliminate virtual methods here will either break current correct usage or will involve significant re-design. If we were to do this re-design, we would most likely feel pressure to eliminate lots of macros in favor of template use (and eliminate some home-grown equivalent of dynamic casting). While this no doubt will lead to cleaner C++ code, templates probably are NOT the way to REDUCE the footprint. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Decision -------- Unclear at this point whether * The proposal does not break things * Any alternate could be produced which is safer * The work needed for the alternative is not unreasonable At this point, we would like to table this suggested enhancement, and see if in the long run it is worth the time and risk. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Plans and Priority ------------------ At this point we are just studying the matter, and it looks like this enhancement may in the end be too costly or too risky. On hold. ================================================================== Enhancement 005: Code-shortening ctor for ZMexClassInfo Statement of suggested enhancement 12/10/01 ---------------------------------- version 2.0.5 S. Snyder points out that each time a user-defined ZMexception is defined, the ctor for its ZMexClassInfo generates more than 3K of code: Most of the code being generated for this file was the static initialization code that calls these ctors for each of the instances. For the usage that i have, for each ZMexClassInfo ctor call, we also have to generate a couple calls to the std::string ctor, plus calls to the ctors cot ZMexHandler, ZMexLogger, ZMexHandleViaParent, and ZMexLogViaParent. This code cannot be shared --- it must be duplicated for each of the ZMexClassInfo objects being constructed. He requests adding a new signature ZMexClassInfo (const char*, const char*, ZMexSeverity = ZMexERROR); [To avoid ambiguities, i think one then should remove the defaults for the s and h args of the existing ctor. For completeness, one might want to add another 3-arg ctor like the above but using std::string instead of const char*.] The definition of this ctor should _not_ be inline, to ensure that we only get one copy of its code. He finds that using this reduces the code to less than 1K per ZMexception. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Technical Information --------------------- What we have is an inline ctor which takes two const strings (rather than references) and has a few defaults which require constructing non-trivial objects. The following mods will deal with all the reasons **we understand** for this code bloat: (1) pass strings as const std::string & -- this in fact should be done throughout the package. (2) Split the ctor such that there is one with just the first 3 args (no defaults for handler or logger) and others which take handler or all three. This way the most common case can use static handler and logger and so need not construct them. (3) Most importantly, move the ctor to a .cc file rather than keeping it inline. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Decision -------- Do these three steps, and ask the user how much this has helped the size. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Plans and Priority ------------------ Put these mods in a December release. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Status of implementation ------------------------- 12/11/01 WB is coding these mods. 12/13/01 Enhancement done and being tested. 12/14/01 It is noted that passing ALL strings as const std::string & has potential for breaking any user code that is using a function as a virtual and overiding the existing signature with the const sstd::string (non-reference). So except for ctors (which is where the problem was noted anyway) we rolled back the general change to references throughout the package. Enhancement doen and tested. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Enhancement Done 12/14/01 ---------------- Version 2.0.6 ================================================================== Enhancement 004: ctor from ostringstream& Statement of suggested enhancement 3/23/01 ---------------------------------- version 2.0.2 M. Paterno requests (for coding convenience) a ctor of ZMexception from an ostringstream&. This facilitates code like if ( user_out_of_line() ) { ostringstream msg; msg << "Deleting filesystem, please stand by..." << ends; // just kidding ZMthrow ( MyException(msg.str())); // MyException inherits from ZMexception. } which would assumedly become if ( user_out_of_line() ) { ostringstream msg; msg << "Deleting filesystem, please stand by..." << ends; // just kidding ZMthrow ( MyException(msg)); // MyException inherits from ZMexception. } " I know this sounds like I'm pretty lazy, but since I've used this a hundred times, I think it would help the code clarity if I could be rid of the explicit call to ostringstream::msg() in my code. " - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Technical Information --------------------- This cannot just go into the base class, it needs also to be in the macro for STANDARD_DEFINITION. Also, to avoid pulling in ostringstream for everybody's code, I need to use rather than in the header file ZMexception.h. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Decision -------- Might as well go ahead with this, it is very safe and costs nothing... - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Plans and Priority ------------------ Doing it, and also slightly improving the signature of the other ctor, which should have been &mesg instead of mesg. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Status of implementation ------------------------- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Enhancement Done x/xx/xx ---------------- ================================================================== ================================================================== Enhancement 003: Override of assigned severity Statement of suggested enhancement 3/23/01 ---------------------------------- version 2.0.1 M. Fischler noticed that while you can set up non-standard handlers and logging behaviors for types of ZMexceptions coming from a library routine, there is no way to assign a severity other than the one it is constructed with (in the library). In one program (which was testing something in HepTuple) it would have been useful to demote a ZMsevere down to ZMwarning. I suggest adding to ZMexception static methods to modify each of the ZMexClassInfo fields set in the constructor: ZMexception::setSeverity(const ZMexSeverity & s); ZMexception::setName(const std::string & name); ZMexception::setFacility(const std::string & facility); - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Technical Information --------------------- The protected member ZMexClassInfo _classInfo is not const; there is no reason why this would not be a trivial mod. Indeed, the ZMexClassInfo already has those three methods; there is just no forwarding method in ZMexception yet. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Decision -------- (At April ZOOM meeting) -- This will be done. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Plans and Priority ------------------ To be done in conjuction with two other enhancements, and released in mid April. Estimated work is (.1 request documetation, done) .1 coding, .1 testing, .1 documentation+release. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Status of implementation ------------------------- * * (in long-running problems might need more than one) * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Enhancement Done 4/11/01 ---------------- version 2.0.2 ================================================================== Enhancement 002: Control of message format Statement of suggested enhancement 3/21/01 ---------------------------------- version 2.0.1 Scott Snyder: In some cases, i do regression testing by capturing the output of test programs and comparing against expected output. The zoom exceptions complicate this because they include information that can vary from run to run and across hosts: the timestamp and the full pathname of the source. For the purpose of regression testing, i put together an alternate logging behavior that suppresses both the timestamp and the leading path components in the exception output. However, it was not entirely straightforward to do this with the interfaces provided, and the result is kind of ugly. It would be much easier if the library provided a global switch to alter the formatting of the exceptions in this manner. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Technical Information --------------------- The idea in the original design was to do such things by creating a custom logging behavior and doing setLogger. Note that this need be done just once for all the descendants of a base type of ZMexception, since the default logger is LogViaParent. I am not sure how I would set things up to provide a global switch; it might be easy or we might run into difficulties. I would suggest that we keep a separation between the ordinary workings and this, by sticking with the original idea of a custom logging behavior. What I should do is take Scott's "kind of ugly" behavior, clean it up and make it into provide a new behavior ZMexLogFormatted. This has the same behavior as ZMexLogAlways, but omits any information which might routinely differ per run. The choice of name ZMexLogFormatted is deliberate: Later, if somebody wants more detailed control (such as "suppress the file completely") this can be provided by methods to modify the default behavior of this new logger, and the change will be locallized to a single class. This mod should be safe if done this way (in that existing behaviors are not affected at all). It will be easy or moderate, depending on how solid Scott's existing behavior code is -- if the concept of stripping down the leading path components is meaningful and portable across all our platforms, this class should be an easy to provide. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Decision -------- (At April ZOOM meeting) -- This will be done. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Plans and Priority ------------------ To be done in conjuction with two other enhancements, and released in mid April. Estimated work is (.1 request documetation, done) .3 coding, .1 testing, .1 documentation+release. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Status of implementation ------------------------- * * (in long-running problems might need more than one) * - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Enhancement Done 4/11/01 ---------------- version 2.0.2 ================================================================== Enhancement 001: ZMthrow with specified line/file Statement of suggested enhancement 3/21/01 ---------------------------------- version 2.0.1 Scott Snyder suggests we provide an alternate version of ZMthrow that allows specifying the file/line number: In most of the code i have that uses the zoom exception classes, I go through a wrapper module.... This serves to reduce coupling; also, in some cases, forming the error message string is nontrivial. The difficultly with this is that if it is done as above, the line number and filename that appear in the exception is that of the ZMthrow call in but what I really want is the line number and filename of the call to . What Scott does is void throw_foo (...) { ... prepare error message s ... ZMthrow (Exc_Foo (s)); } and then call throw_foo() rather than using ZMthrow directly. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Technical Information --------------------- At first sight, this still looked like a request we could solve without any changes in the package: The ZMthrow macro uses the ZMthrow_ function, doing ZMthrow_( userExcept, __LINE__, __FILE__ ). So the user with his own file/line number could call ZMthrow_ explicitly, and provide whatever remembered file/line strings are desired. Turns out this is too hasty: The ZMthrow macro does two additional things, namely it tests the return of ZMthrow_ and decides whenther to (a) abort() if exceptions are not enabled, or (b) throw the ZMexception otherwise. So some form of macro or method is indeed desirable to do this. Too bad ZMthrow has to be a macro (to get the proper line number in the normal case) so we can't just provide the signature to take optional line and file arguments. I think the cleanest syntax that would help is a method ZMthrow_from ( ZMexception & ex, int line, std::string file ); Scott would then be able to do: throw_foo ( __LINE__, __FILE__ ); with void throw_foo (int line, std::string file) { ... prepare error message s ... ZMthrow_from (Exc_Foo (s), line, file); } The implementation will be easy and safe. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Decision -------- (At April ZOOM meeting) -- This will be done. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Plans and Priority ------------------ To be done in conjuction with two other enhancements, and released in mid April. Estimated work is (.1 request documetation, done) .1 coding, .1 testing, negligible documentation+release. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Status of implementation ------------------------- Done and tested as of 4/9/01 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Enhancement Done 4/10/01 ---------------- version 2.0.2 ==================================================================