Re: [Python-Dev] LSB: pyc stability

2006-12-04 Thread Neil Toronto
Martin v. Löwis wrote:
> Brett Cannon schrieb:
>   
>> Did they say why they wanted to distribute  bytecode files?  I assume it
>> is either for space considerations or they think it will help to protect
>> their IP somehow.
>> 
>
> It's to protect the IP (i.e. for proprietary software). They are aware
> of decompyle, but still consider byte-code only distribution of their
> code necessary for protection.

It sounds like a trade secret issue. You have to take reasonable 
measures to protect trade secrets in order for them to be legally 
recognized as such. I wouldn't be surprised if compiling to bytecode 
counts. There are similar provisions in copyright due to the DMCA (which 
seems to require nothing stronger than, say, ROT26), but I don't think 
this is the right context for that.

Space considerations shouldn't be much of an issue, since you can (and 
should in many cases) distribute your code in a ZIP file, and code 
compresses quite well. Can Python import modules from encrypted ZIP 
files? That'd be an interesting way to protect a trade secret, and 
probably safer (in the courts) than distributing bytecode.

Neil


___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Deletion order when leaving a scope?

2007-01-18 Thread Neil Toronto
Thomas Wouters wrote:
> On 1/18/07, *Larry Hastings* <[EMAIL PROTECTED] 
> > wrote:
>
>
>
> I just ran a quickie experiment and determined: when leaving a
> scope, variables are deleted FIFO, aka in the same order they were
> created.  This surprised me; I'd expected them to be deleted LIFO,
> aka last first.  Why is it thus?  Is this behavior an important
> feature or an irrelevant side-effect?
>
>
> Please regard it as an irrelevant side-effect. If you want objects to 
> be cleaned up in a particular order, you should enforce it by having 
> one of them refer to the other. A great many details can affect the 
> order in which variables are cleaned up, and that only decreases 
> refcounts of the actual objects -- a great many other details can then 
> affect the order in which any objects left with a 0 refcount are 
> actually cleaned up. Even not counting the more complicated stuff like 
> GC and funky __del__ methods, just having 'import *' or a bare 'exec' 
> in your function can change the order of DECREFs.

I imagine this would be important to someone expecting system resources 
to be cleaned up, closed, deallocated, or returned inside of __del__ 
methods. Someone coming from C++ might expect LIFO behavior because 
common idioms like RAII (Resource Allocation Is Instantiation) don't 
work otherwise. A Java programmer wouldn't care, being used to cleaning 
up resources manually with a try...catch...finally.

I'm just putting a possible motivation on the concern. It happens that 
the Pythonic Way is also the Java Way in this area: don't expect any 
specific deletion order (don't even expect a guaranteed call to 
__del__), and manually clean up after yourself. As a warning, this has 
been the subject of a great many flame wars between C++ and Java 
programmers...

Neil

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] New syntax for 'dynamic' attribute access

2007-02-11 Thread Neil Toronto
Ben North wrote:
> Hi,
>
> A few days ago I posted to python-ideas with a suggestion for some new
> Python syntax, which would allow easier access to object attributes
> where the attribute name is known only at run-time. For example:
>
> setattr(self, method_name, getattr(self.metadata, method_name))
>
> from Lib/distutils/dist.py could be rewritten
>
> self.(method_name) = self.metadata.(method_name)

I like it.

> The new syntax would also be usable in augmented assignments, as in
>
> obj.(attr_name) += 1

Even nicer; much, much better than the current spelling.

> *snip*
>
> * The draft currently allows a two-argument form, to supply a default
> value if the object has no attribute of that name. This mimics the
> behaviour of the three-argument form of getattr, but looks a bit wrong:
>
> s = obj.(attr_name, 'default string')
>
> I agree that it looks odd, but perhaps the extra expressive power
> gained might be worth the oddness.

It's not just odd, but because you can't use the result of that syntax 
as an assignment target (according to the PEP), it smells special-casey.

Neil

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] New syntax for 'dynamic' attribute access

2007-02-11 Thread Neil Toronto
Anthony Baxter wrote:
> I have to say that I'm not that impressed by either the 1-arg or 
> 2-arg versions. Someone coming across this syntax for the first 
> time will not have any hints as to what it means - and worse, it 
> looks like a syntax error to me. -1 from me.
>   

I'm not sure the "looks like a syntax error" argument holds much weight, 
because any new syntax is likely to be a syntax error until the syntax 
is changed. :) "No hints" is a decent argument against it, though. 
Parenthesis are already used for tuples, function calls, precedence, and 
generator comprehensions. The more something gets overloaded, the more 
ambiguous it looks. How about

   obj.*str_expression

instead? "*" is pretty common in the C family of languages as a 
dereferencing operator.

Neil

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] PATCH: Fast globals/builtins lookups for 2.6

2007-11-29 Thread Neil Toronto
I've posted a patch here:

http://bugs.python.org/issue1518

for 2.6a0 that speeds up LOAD_GLOBAL to where it's just barely slower 
than LOAD_FAST for both globals and builtins. It started life here, in 
Python-ideas:

http://mail.python.org/pipermail/python-ideas/2007-November/001212.html

The idea is to cache pointers to dictionary entries rather than 
dictionary values as is usually suggested for speeding up globals. In my 
original approach, every dictionary would keep a list of "observers" 
that it would notify when an entry pointer became invalid. However, the 
surgery on PyDictObject became too invasive, to the point where the new 
code was affecting performance of unrelated code paths. (It was probably 
caching issues.) It also made some (very rare) operations on builtins 
and globals very, very slow.

The new approach tags each PyDictObject with a "version": a 64-bit value 
that is incremented for every operation that invalidates at least one 
entry pointer. (Those are inserting set, delete, pop, clear and resize. 
Non-inserting set and get are unaffected.) In this approach, changes to 
PyDictObject are uninvasive and do not affect performance in any 
measurable way (as far as I can tell).

Every function has a PyFastGlobalsObject, which keeps entry pointers for 
everything in co_names and tracks its dicts' versions so it can update 
the pointers when one might have become invalid. LOAD_GLOBALS uses the 
PyFastGlobalsObject to get globals and builtins by name index rather 
than by string key.

With the patch, Python behaves differently in these two ways (as far as 
I can tell):

1. As before, a __builtins__ ({'None': None}) is created for frames 
whose globals do not have one. Unlike before, it's added to the globals 
dict rather than just kept internally. This made implementation easier - 
I don't think it's a big deal (but I might be wrong).

2. A change of __builtins__ (its value, not its contents) always appears 
at the beginning of a stack frame. (Before, changing __builtins__ in a 
module would be undetectable if function calls were kept within that 
module.) This is likely of little importance.

I'd love to see it included. I have donned my asbestos underwear and my 
best chain mail shirt and I'm begging for comments.

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] [poll] New name for __builtins__

2007-11-29 Thread Neil Toronto
Christian Heimes wrote:
> Greg Ewing wrote:
>> __uberglobal__
> 
> Since Python 3.0 supports all unicode chars I vote for __überglobal__.

Make it untypeable to most Americans so as to discourage use? If that's 
what we're going for, I suggest the somewhat more self-documenting and 
less impossible __the_dictionary_where_all_the_builtins_are_now__.

Seriously, though, I really liked __universal__. It's part of a theme: 
local < global < universal, and it communicates itself well. __root__ 
and its ilk don't bring anything concrete to mind, just abstract trees. 
I don't think of namespaces as trees when I'm coding a function - 
they're more like layers or overlays at that level.

So, a +0.01 from me (after weighting for lurkerhood) for __universal__.

Neil

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PATCH: Fast globals/builtins lookups for 2.6

2007-11-29 Thread Neil Toronto
Guido van Rossum wrote:
> Cool! Can't wait to get my hands on it. How does it affect pystone?

Pystone likes it, according to my tests and Chris's. On his machine, if 
I'm reading these stones right, it takes about 7% off the run time on 
average. On mine it takes off 4%.

> What happens if the globals are not a real dict but an instance of
> another collections.MutableMapping (virtual or real) subclass?

Globals has to be a real dict or a subclass, because otherwise 
PyFastGlobalsObject won't be able to point directly at its entries. This 
doesn't change anything, since globals had to be a real dict or subclass 
before.

> We've worked hard (well, some folks have) to enable this. It would be
> a show-stopper if this broke (or changed semantics or became
> significantly slower).

Besides what I outlined about __builtins__ (which should be an arbitrary 
implementation detail), everything is exactly the same. The details of 
fast globals are completely transparent to everything but PyDictObject 
(in which they're nearly insignificant) and PyFastGlobalsObject. In 
other words, every other bit of code in the interpreter can happily do 
whatever the heck it wants with globals and builtins without having to 
worry about messing anything up. Since it's nearly transparent to the 
interpreter core, Python-the-language shouldn't see any differences at all.

But then, I know less about the rest of the core than just about 
everybody else here, so I may just be talking out of my rear. :)

Pystone and my microbenchmarks look good, but we don't know yet about 
Pybench. On my tests, it's nearly the same, with small variations in 
individual tests. On Chris's, there are large variations that appear (to 
me) to be random. Pybench does almost nothing with globals, though - the 
numbers on that really only need to stay put.

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PATCH: Fast globals/builtins lookups for 2.6

2007-11-29 Thread Neil Toronto
Guido van Rossum wrote:
> Hm.
> 
> On my Linux box, in the trunk:
> 
> Before the patch:
> Pystone(1.1) time for 5 passes = 1.16
> This machine benchmarks at 43103.4 pystones/second
> 
> After the patch:
> Pystone(1.1) time for 5 passes = 1.14
> This machine benchmarks at 43859.6 pystones/second
> 
> That's only about 1.75% faster. But pystone is a lousy benchmark.

I'm not aware of any benchmark that isn't. :)

Can you humor me and change the PY_LONG_LONG to Py_ssize_t in both 
PyDictObject and PyFastGlobalsObject and see if that helps? It does on 
one of my test machines.

Speaking of which, here's a question for everybody. I was wondering 
whether 64 bits is necessary. It takes an hour of concerted effort - 
nothing but "module.d = 1; del module.d" for an hour straight - to 
overflow a 32-bit version number. Is anybody going to actually get close 
to doing that in a global namespace?

I don't think a malicious user could exploit it. The most they could do 
is segfault by doing exactly 2**32 entry-invalidating operations and 
then one get or set. They've got better things to do if they're running 
code on your machine.

FWIW - and I wouldn't bother with this if I weren't mucking about with 
dict internals - with a 32-bit version number, I've verified that gcc 
emits only one extra instruction in dict functions that increment it. 
It's two for a 64-bit number. The version test in LOAD_GLOBAL does take 
a bit more time with 64 bits, though.

Neil

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] [poll] New name for __builtins__

2007-11-30 Thread Neil Toronto
Fred Drake wrote:
> On Nov 30, 2007, at 6:05 PM, Guido van Rossum wrote:
>> It's almost as if nobody has seen my proposal to leave __builtins__
>> alone and rename the __builtin__ module instead.
> 
> 
> I suspect that's indistinguishable from everyone being tired of the  
> discussion, knowing that you're going to pick something reasonable in  
> spite of our yammering.
> 
> +1 for a module named "builtin", or something similarly obscure.

Would it be too confusing to call it "builtins"?

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PATCH: Fast globals/builtins lookups for 2.6

2007-11-30 Thread Neil Toronto
Steve Holden wrote:
> Neil Toronto wrote:
>> Speaking of which, here's a question for everybody. I was wondering 
>> whether 64 bits is necessary. It takes an hour of concerted effort - 
>> nothing but "module.d = 1; del module.d" for an hour straight - to 
>> overflow a 32-bit version number. Is anybody going to actually get close 
>> to doing that in a global namespace?
>>
> Of course not. And 640k is as much memory as anyone could reasonably 
> need ...

Point taken - forget I asked.

Neil

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] -O2 faster than -O3?

2007-11-30 Thread Neil Toronto
On both of my systems, using -O2 reduces execution time in pystone by 9% 
and in pybench by 8%. It's function inlining: "-O3 
-fno-inline-functions" works just as well as "-O2". Removing "-g" has 
little effect on the result.

Systems:
  - AMD Athlon 64 X2 Dual Core 4600+, 512 KB cache (desktop)
  - Intel T2300 Dual Core 1.66GHz, 512 KB cache (laptop)

Both are Ubuntu 7.04, GCC 4.1.2.

Does anybody else see this?

It may be GCC being stupid (which has happened before) or not enough 
cache on my systems (definitely possible). If it's not one of those, I'd 
say it's because CPython core functions are already very large, and 
almost everything that ought to be inlined is already a macro.

Pybench comparison for the Athlon:

http://spreadsheets.google.com/ccc?key=pHIJrYc_pnIXCwJvDvU9gfQ&hl=en_US

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] -O2 faster than -O3?

2007-11-30 Thread Neil Toronto
Neal Norwitz wrote:
> On Nov 30, 2007 7:16 PM, Brett Cannon <[EMAIL PROTECTED]> wrote:
>> On Nov 30, 2007 12:02 PM, Neil Toronto <[EMAIL PROTECTED]> wrote:
>>> On both of my systems, using -O2 reduces execution time in pystone by 9%
>>> and in pybench by 8%. It's function inlining: "-O3
>>> -fno-inline-functions" works just as well as "-O2". Removing "-g" has
>>> little effect on the result.
>>>
>>> Systems:
>>>   - AMD Athlon 64 X2 Dual Core 4600+, 512 KB cache (desktop)
>>>   - Intel T2300 Dual Core 1.66GHz, 512 KB cache (laptop)
>>>
>>> Both are Ubuntu 7.04, GCC 4.1.2.
>>>
>>> Does anybody else see this?
>>>
>>> It may be GCC being stupid (which has happened before) or not enough
>>> cache on my systems (definitely possible). If it's not one of those, I'd
>>> say it's because CPython core functions are already very large, and
>>> almost everything that ought to be inlined is already a macro.
>>>
>> That's quite possible.  Previous benchmarks by AMK have shown that
>> perhaps -0m (or whatever the flag is to optimize for size) sometimes
>> is the best solution.  It has always been believed that the eval loop
>> is already large and manages to hit some cache sweet spot.
> 
> The flag is -Os.  I suspect you will do better to limit the size of
> inlining rather disabling it completely.  The option is
> -finline-limit=number.  I don't know the default value or what you
> should try.  I would be interested to hear more results though.

I've got some pystones (50) results for the Athlon. The default for 
-finline-limit is 600. This is for the current trunk.

Global optionspystones/sec (median of 3)
--
-O3  50454.1
-O2  57273.8
-Os  52798.3
-O3 -fno-inline-functions54824.6
-O3 -finline-limit=300   51229.7
-O3 -finline-limit=150   51177.7
-O3 -finline-limit=7551759.8
-O3 -finline-limit=2553821.3

ceval.c options (-O3 for others)  pystones/sec (median of 3)
---   
-O2  55066.1
-Os  57012.5
-O3 -fno-inline-functions55679.3
-O3 -finline-limit=300   51440.3
-O3 -finline-limit=150   50916.5
-O3 -finline-limit=7551387.5
-O3 -finline-limit=2552631.6

Now that's interesting. -O2 seems to be the best global option, and -Os 
seems to be best for ceval.c. One more test then:

Global -O2, ceval.c -Os  56753.7

Weird.

If you're going to run these benchmarks yourself, make sure you "make 
clean" before building with different options. (I don't know why it's 
necessary, but it is.) To change options for just ceval.c, add this to 
Makefile.pre.in under "Special rules":

Python/ceval.o: $(srcdir)/Python/ceval.c
 $(CC) -c $(PY_CFLAGS) -Os \
 -o $@ $(srcdir)/Python/ceval.c

The last -O flag should override any other.

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] [poll] New name for __builtins__

2007-11-30 Thread Neil Toronto
Terry Reedy wrote:
> "Greg Ewing" <[EMAIL PROTECTED]> wrote in message 
> news:[EMAIL PROTECTED]
> | I think the situation with __main__ is different from __builtin__,
> 
> I effectively agreed by not disputing Guido's response ;-) 

Very cunning. But I was even more cunning, and didn't even *consider* 
disputing Guido's response.

Neil

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] Non-string keys in namespace dicts

2007-12-01 Thread Neil Toronto
Are there any use-cases for allowing namespace dicts (such as globals, 
builtins and classes) to have non-string keys? I'm asking because I'm 
planning on accelerating method lookups next, and the possibility of a 
key compare changing the underlying dict could be a major pain. (It was 
a minor pain for globals.)

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Non-string keys in namespace dicts

2007-12-02 Thread Neil Toronto
Nicko van Someren wrote:
> On 2 Dec 2007, at 03:09, Neil Toronto wrote:
> 
>> Are there any use-cases for allowing namespace dicts (such as globals,
>> builtins and classes) to have non-string keys? I'm asking because I'm
>> planning on accelerating method lookups next, and the possibility of a
>> key compare changing the underlying dict could be a major pain. (It was
>> a minor pain for globals.)
> 
> The only plausible use case I can think of might be wanting to use ints 
> or longs as keys, though I've never seen it done.  Of course this would 
> be trivial to code around and it seems very much a fringe case, so I'd 
> be in favour of deprecating non-string namespace keys if it's going to 
> make look-ups go faster.

If you insert non-string keys into a namespace dict it'll slow down 
lookups already. :) The dict will switch to the more general lookdict 
from lookdict_string. Looks like it's just a bad idea all around.

It turned out not *that* hard to code around for attribute caching, and 
the extra cruft only gets invoked on a cache miss. The biggest problem 
isn't speed - it's that it's possible (though extremely unlikely), while 
testing keys for equality, that a rich compare alters the underlying 
dict. This causes the caching lookup to have to try to get an entry 
pointer again, which could invoke the rich compare, which might alter 
the underlying dict...

This problem already exists for general dicts with non-string keys (it 
can blow the C stack) and attribute caching makes it a bit more likely 
(the compare only has to insert or delete an item rather than cause a 
resize), so it'd be nice if it didn't apply to identifiers.

As far as I know, though, the only way to get non-string keys into a 
class dict is by using a metaclass.

Anyway, report: I've got an initial working attribute cache, using the 
conveniently-named-and-left-NULL tp_cache. It's a nice speedup - except 
on everything the standard benchmarks test, because their class 
hierarchies are very shallow. :p  If an MRO has more than two classes in 
it, every kind of lookup (class method, object method, object attribute) 
is faster. Having more than four or five makes things like self.variable 
take less than half the time.

It'd be nice to have a benchmark with a deep class hierarchy. Does 
anybody know of one?

I'm working on making it as fast as the original when the MRO is short. 
Question for Guido: should I roll this into the fastglobals patch?

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Non-string keys in namespace dicts

2007-12-03 Thread Neil Toronto
Guido van Rossum wrote:
> On Dec 2, 2007 12:49 PM, Neil Toronto <[EMAIL PROTECTED]> wrote:
>> It turned out not *that* hard to code around for attribute caching, and
>> the extra cruft only gets invoked on a cache miss. The biggest problem
>> isn't speed - it's that it's possible (though extremely unlikely), while
>> testing keys for equality, that a rich compare alters the underlying
>> dict. This causes the caching lookup to have to try to get an entry
>> pointer again, which could invoke the rich compare, which might alter
>> the underlying dict..
> 
> How about subclasses of str? These have all the same issues...

Yeah. I ended up having it, per class, permanently revert to uncached 
lookups when it detects that a class dict in the MRO has non-string 
keys. That's flagged by lookdict_string, which uses PyString_CheckExact.

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Non-string keys in namespace dicts

2007-12-03 Thread Neil Toronto
Phillip J. Eby wrote:
> At 12:27 PM 12/3/2007 -0700, Neil Toronto wrote:
>> Guido van Rossum wrote:
>> > How about subclasses of str? These have all the same issues...
>>
>> Yeah. I ended up having it, per class, permanently revert to uncached
>> lookups when it detects that a class dict in the MRO has non-string
>> keys. That's flagged by lookdict_string, which uses PyString_CheckExact.
> 
> I'm a bit confused here.  Isn't the simplest way to cache attribute 
> lookups to just have a cache dictionary in the type, and update that 
> dictionary whenever a change is made to a superclass?  That's 
> essentially how __slotted__ attribute changes on base classes work now, 
> isn't it?  Why do we need to mess around with the dictionary entries 
> themselves in order to do that?

The nice thing about caching pointers to dict entries is that they don't 
change as often as values do. There are fewer ways to invalidate an 
entry pointer: inserting set, resize, clear, and delete. If you cache 
values, non-inserting set could invalidate as well.

Because inserting into namespace dicts should be very rare, caching 
entries rather than values should reduce the number of times cache 
entries are invalidated to near zero. Updating is expensive, so that's 
good for performance.

Rare updating also means it's okay to invalidate the entire cache rather 
than single entries, so the footprint of the caching mechanism in the 
dict can be very small. For example, I've got a single 64-bit counter in 
each dict that gets incremented after every potentially invalidating 
operation. That comes down to 8 bytes of storage and two extra machine 
instructions (currently) per invalidating operation. The cache checks it 
against its own counter, and updating ensures that it's synced.

Some version of the non-string keys problem would exist with any caching 
mechanism, though. An evil rich compare can always monkey about with 
class dicts in the MRO. If a caching scheme caches values and doesn't 
account for that, it could return stale values. If it caches entries and 
doesn't account for that, it could segfault. I suppose you could argue 
that returning stale values is fitting punishment for using an evil rich 
compare, though the punishee isn't always the same person as the punisher.

Neil

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Non-string keys in namespace dicts

2007-12-03 Thread Neil Toronto
Phillip J. Eby wrote:
> At 03:26 PM 12/3/2007 -0700, Neil Toronto wrote:
>> Phillip J. Eby wrote:
>> > At 12:27 PM 12/3/2007 -0700, Neil Toronto wrote:
>> Some version of the non-string keys problem would exist with any caching
>> mechanism, though. An evil rich compare can always monkey about with
>> class dicts in the MRO. If a caching scheme caches values and doesn't
>> account for that, it could return stale values. If it caches entries and
>> doesn't account for that, it could segfault. I suppose you could argue
>> that returning stale values is fitting punishment for using an evil rich
>> compare, though the punishee isn't always the same person as the 
>> punisher.
> 
> Actually, you're missing the part where such evil code *can't* muck 
> things up for class dictionaries.  Type dicts aren't reachable via 
> ordinary Python code; you *have* to modify them via setattr.  (The 
> __dict__ of types returns a read-only proxy object, so the most evil 
> rich compare you can imagine still can't touch it.)

Interesting. But I'm going to have to say it probably wouldn't work as 
well, since C code can and does alter tp_dict directly. Those places in 
the core would have to be altered to invalidate the cache. There's also 
the issue of extensions, which so far have been able to alter any 
tp_dict without problems. It'd also be really annoying for a class to 
have to notify all of its subclasses when one of its attributes changed.

In other words, I can see the footprint being rather large and difficult 
to manage. By hooking right into dicts and letting them track when 
things change, every other piece of code in the system can happily 
continue doing whatever it likes without needing to worry that it might 
invalidate some cache entry somewhere. I'm confident that's the right 
design choice whether it's best to cache entries or not.

I hope you don't feel that I'm just trying to be contradictory. I'm 
actually enjoying the discussion a lot. I'd rather have my grand ideas 
tested now than discover I was wrong later.

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Non-string keys in namespace dicts

2007-12-03 Thread Neil Toronto
Phillip J. Eby wrote:
> At 03:51 PM 12/3/2007 -0800, Guido van Rossum wrote:
>> On Dec 3, 2007 3:48 PM, Phillip J. Eby <[EMAIL PROTECTED]> wrote:
>> > Actually, you're missing the part where such evil code *can't* muck
>> > things up for class dictionaries.  Type dicts aren't reachable via
>> > ordinary Python code; you *have* to modify them via setattr.  (The
>> > __dict__ of types returns a read-only proxy object, so the most evil
>> > rich compare you can imagine still can't touch it.)
>>
>> What's to prevent that evil comparison to call setattr on the class?
> 
> If you're caching values, it should be sufficient to have setattr 
> trigger the invalidation.  For entries, I have to admit I don't 
> understand the approach well enough to make a specific proposal.

As long as you could determine whether PyDict_SetItem inserted a new 
key, it would make sense. (If it only updates a value, the cache doesn't 
need to change because the pointer to the entry is still valid and the 
entry points to the new value.) The PyDict_SetItem API would have to 
change, or the dict would have to somehow pass the information 
out-of-bound. Neither option sounds great to me, so I'd go with caching 
values from setattr.

Neil

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Non-string keys in namespace dicts

2007-12-03 Thread Neil Toronto
I apologize - I had forgotten what you were telling me by the time I 
replied. Here's a better answer.

> Phillip J. Eby wrote:
>> At 03:26 PM 12/3/2007 -0700, Neil Toronto wrote:
>> Actually, you're missing the part where such evil code *can't* muck 
>> things up for class dictionaries.  Type dicts aren't reachable via 
>> ordinary Python code; you *have* to modify them via setattr.  (The 
>> __dict__ of types returns a read-only proxy object, so the most evil 
>> rich compare you can imagine still can't touch it.)

C code can and does alter tp_dict directly already. If caching were 
implemented within type's setattr, all these places would have to be 
changed to use setattr only. That doesn't seem so bad at first. It's a 
change in convention, certainly: a new informal rule that says "no 
monkeying with a PyTypeObject's tp_dict, period". Lack of observance 
could be difficult to debug, as a PyDict_SetItem would appear to have 
worked just fine to C code but not show up to Python code.

Neil

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Non-string keys in namespace dicts

2007-12-03 Thread Neil Toronto
Phillip J. Eby wrote:
> At 10:17 PM 12/3/2007 -0700, Neil Toronto wrote:
>> Interesting. But I'm going to have to say it probably wouldn't work as
>> well, since C code can and does alter tp_dict directly. Those places in
>> the core would have to be altered to invalidate the cache.
> 
> Eh?  Where is the type dictionary altered outside of setattr and class 
> creation?

You're right - my initial grep turned up stuff that looked like tp_dict 
monkeying out of context. The ctypes module does it a lot, but only in 
its various *_new functions.

>> It'd also be really annoying for a class to
>> have to notify all of its subclasses when one of its attributes changed.
> 
> It's not all subclasses - only those subclasses that don't shadow the 
> attribute.  Also, it's not necessarily the case that notification would 
> be O(subclasses) - it could be done via a version counter, as in your 
> approach.  Admittedly, that would require an extra bit of indirection, 
> since you'd need to keep (and check) counters for each descriptor.

And the extra overhead comes back to bite us again, and probably in a 
critical path. (I'm sure you've been bitten in a critical path before.) 
That's been the issue with all of these caching schemes so far - Python 
is just too durned dynamic to guarantee them anything they can exploit 
for efficiency, so they end up slowing down common operations. (Not that 
I'd change a bit of Python, mind you.)

For example, almost everything I've tried slows down attribute lookups 
on built-in types. Adding one 64-bit version counter check and a branch 
on failure incurs a 3-5% penalty. That's not the end of the world, but 
it makes pybench take about 0.65% longer.

I finally overcame that by making a custom dictionary type to use as the 
cache. I haven't yet tested something my caching lookups are slower at - 
they're all faster so far for builtins and Python objects with any size 
MRO - but I haven't tested exhaustively and I haven't done failing 
hasattr-style lookups. Turns out that not finding an attribute all the 
way up the MRO (which can lead to a persistent cache miss if done with 
the same name) is rather frequent in Python and is expected to be fast. 
I can cache missing attributes as easily as present attributes, but they 
could pile up if someone decides to hasattr an object with a zillion 
different names.

I have a cunning plan, though, which is probably best explained using a 
patch.

At any rate, I'm warming to this setattr idea, and I'll likely try that 
next whether my current approach works out or not.

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


[Python-Dev] PATCH: attribute lookup caching for 2.6

2007-12-05 Thread Neil Toronto
So Jim and PJE finally convinced me to do it the right way. :) Thanks 
guys - it turned out very nice.

http://bugs.python.org/issue1560

http://spreadsheets.google.com/ccc?key=pHIJrYc_pnIUpTm6QSG2gZg&hl=en_US

It caches type/metatype attribute lookups, including missing attributes. 
Summary of the bug tracker issue:

- Successful attribute lookups are 20% faster, even for classes with 
short MROs and (probably most) builtins - haven't tested unsuccessful 
lookups

- Successful hasattr is 5-10% faster, unsuccessful is 5% faster (less 
impressive than above, and likely due to overhead - internally, all 
lookups are the same)

- list.__init__ and list().__init__ are slower, and I can't figure out 
why (creating instances of subclasses of list will be a little slower, 
and this may show up in other builtin types)

- I haven't benchmarked type attribute sets (how much do we care?) - it 
should be quite a bit faster than updating a slot, though

- Caching missing attributes is crucial for good performance

- The CreateNewInstances benchmark uncovered an issue that needs fixing; 
please see the tracker for details

All kinds of commentary and feedback is most welcome.

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PATCH: attribute lookup caching for 2.6

2007-12-05 Thread Neil Toronto
Phillip J. Eby wrote:
> At 10:48 PM 12/5/2007 +0100, Georg Brandl wrote:
>> Neil Toronto schrieb:
>>> So Jim and PJE finally convinced me to do it the right way. :) Thanks
>>> guys - it turned out very nice.
>> How does this relate to Armin Rigo's method cache patch?
>>
>> (http://bugs.python.org/issue1685986)
> 
> Interesting.  Armin's approach uses a single global cache of up to 
> 1024 descriptors.  That seems a lot simpler than anything I thought 
> of, and might perform better by encouraging the processor to keep the 
> descriptors in cache.  It has a lot less pointer indirection, and has 
> a dirt-simple way of invalidating a class' entries when something changes.

Hey, I took out all my extra pointer indirection. :p

FWIW, I like it. Though the hash should really incorporate the hash of 
the type name as well as the attribute's so that sometype.method calling 
othertype.method doesn't invalidate the cache. Locality makes the global 
cache work, but locality also often means re-using the same names.

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PATCH: attribute lookup caching for 2.6

2007-12-05 Thread Neil Toronto
Phillip J. Eby wrote:
> At 07:43 PM 12/5/2007 -0700, Neil Toronto wrote:
>> FWIW, I like it. Though the hash should really incorporate the hash of
>> the type name as well as the attribute's so that sometype.method calling
>> othertype.method doesn't invalidate the cache. Locality makes the global
>> cache work, but locality also often means re-using the same names.
> 
> Look at the patch more closely.  The hash function uses a version number 
> times the method name's hash.  "Version" numbers are assigned one per 
> class, so unless there are 2**32 classes in the system, they are 
> uniquely numbered.  The multiplication and use of the high bits should 
> tend to spread the hash locations around and avoid same-name collisions.

Good grief - how did I miss that? I plead parenthesis. They threw me off.

So I've applied Armin's patch to 2.6 (it was nearly clean) and am 
playing with it. cls.name lookups are 15-20% faster than mine, and 
inst.name lookups are 5-10% faster. His is also winning on hasattr calls 
(succeeding and failing) on classes, but mine is winning on hasattr 
calls on instances. I want to poke at it a bit to find out why.

On pybench, his is faster at BuiltinMethodLookups, significantly faster 
at CreateNewInstances, and a bit faster at almost everything else. 
BuiltinFunctionCalls is slower - slower than stock - it might need 
poking there, too.

In all, it's a lovely piece of work.

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PATCH: attribute lookup caching for 2.6

2007-12-06 Thread Neil Toronto
Kevin Jacobs <[EMAIL PROTECTED]> wrote:
> On Dec 6, 2007 1:35 AM, Neil Toronto <[EMAIL PROTECTED] 
> <mailto:[EMAIL PROTECTED]>> wrote:
> 
> So I've applied Armin's patch to 2.6 (it was nearly clean) and am
> playing with it. cls.name <http://cls.name> lookups are 15-20%
> faster than mine, and
> inst.name <http://inst.name> lookups are 5-10% faster. His is also
> winning on hasattr calls
> (succeeding and failing) on classes, but mine is winning on hasattr
> calls on instances. I want to poke at it a bit to find out why.
> 
> 
> I hope folks have noticed that I've done some significant cleanup and 
> forward porting some months ago at
> 
> http://bugs.python.org/issue1700288

Excellent. I tried this as well. This is guarding cache access with 
PyString_CheckExact (as it should) rather than asserting PyString_Check, 
plus a few other cleanups. It runs nearly as fast as Armin's, and still 
faster than mine and much faster than without.

Neil

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] PEP: Lazy module imports and post import hook

2008-01-09 Thread Neil Toronto
Aside:

Nick Coghlan wrote:
> My main concern is that the import lock is something Python users 
> typically don't have to worry about (aside from the 'don't spawn a 
> thread as a side effect of importing' guideline)...

I've never heard of this and I can't get Google to find it. Is it a 
deadlock problem?

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] Python 3000: Special type for object attributes & map keys

2008-03-19 Thread Neil Toronto
Greg Ewing wrote:
> Neal Norwitz wrote:
>> Part of this is done, but very differently in that all strings used in
>> code objects are interned (stored in a dictionary
> 
> And since two interned strings can be compared
> by pointer identity, I don't see how this differs
> significantly from the "unique integer" idea.
> 
> If the integers were used to directly index an
> array instead of being used as dict keys, it
> might make a difference. The cost would be that
> every namespace would need to be as big as
> the number of names in existence, with most
> of them being extremely sparse.

And we already have a data structure for sparse arrays... it's called a 
"dict". :)

If every attribute name were guaranteed to be an interned string (not 
currently the case - attribute names can be any kind of object), it 
might be possible to add another dict specialization for interned string 
lookup. The wins would be that lookup could assume the string's hash is 
valid, and equality comparison could be done via pointer comparison. 
HOWEVER...

I think that the attribute cache patches that went into 2.6 and 3.0 
mostly take care of lookup speed issues. They both assume strings are 
interned already. A cache hit consists of calculating a cache index from 
the string hash, ensuring that the attribute name at that index is 
identical (via pointer comparison) to the attribute name to be looked 
up, and returning the associated value. Lookup with an attribute that's 
not a string or not interned is automatically a cache miss, and it 
happens very rarely.

Specializing dicts for interned strings would optimize the cache miss. 
(When I was making the 3.0 patch, I found that happened rarely on the 
benchmarks and regression tests. It was somewhere around 5%.) The cache 
miss isn't expensive just because of the dict lookup. The attribute has 
to be searched for in every type and super-type of the object. The 
occasional string equality test probably doesn't register.

I'd be happy to be shown to be wrong, though.

Neil
___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com


Re: [Python-Dev] A thought on generic functions

2008-05-30 Thread Neil Toronto

Greg Ewing wrote:

Paul Moore wrote:

I'd rather see a solution which addressed the
wider visitor use case (I think I just sprained my back bending over
backwards to avoid mentioning generic functions :-))


Speaking of generic functions, while thinking about the
recent discussion on proxy objects, it occurred to me
that this is something you can do with an OO system
that you can't do so easily with a generic function
system. If the operations being proxied were generic
functions rather than methods, you'd have to override
them all individually instead of having a central point
to catch them all.


It depends on your dispatch rules. Say the implementation orders the 
candidates lexically (like default CLOS). This is equivalent to choosing 
as first candidates the set of functions with the most specific first 
argument. Resolution for a generic function call and generic method call 
are semantically the same, so there's no reason not to have the latter, 
and proxying by __getattr__ tricks becomes doable again.


Neil

___
Python-Dev mailing list
[email protected]
http://mail.python.org/mailman/listinfo/python-dev
Unsubscribe: 
http://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com