Does Python (or psyco) already do this optimisation?

Mike C. Fletcher mcfletch at rogers.com
Thu Nov 21 01:56:31 EST 2002


General idea:
    Have namespaces provide pointer-addresses in which the current 
PyObject * of a given name is stored.  Provide hooks on namespaces which 
catch set/del of names to update cached values.  Have compiled methods 
store an index into the local namespace's array of pointer-addresses in 
which to look for a name (going up the lexical namespace chain) rather 
than using hashtable lookups.

Simplistic approach:

    * For each namespace:
          o table [N*M pointer-to-pointers] (N=number of names,
            M=lexical depth, stores local-namespace pointer-location and
            all parent-namespace's pointer-locations (yes, that's
            inefficient when it could just point to the parent's
            pointer-to-pointer location, but that seems a little
            convoluted))
          o Hash-map { name: tableOffset }  (tableOffset being index
            into table, all items added to the hash must be present in
            the table)
          o Parent-namespace-pointer (for use during standard
            name-resolution passes)
    * For each name in a code object, store the tableOffset for the name
      into the namespace's table for that name. Note that you must
      ensure the name exists in all parent tables as well
    * To resolve, each compiled method checks each namespace's pointer
      in turn.  If the pointer is NULL, it tries the next namespace in
      the chain.  If none of the pointers is non-NULL, do a full
      namespace lookup and cache the result in the appropriate
      namespace-pointer (or raise a NameError on failing).  If a pointer
      is non-NULL, go ahead and use it.
    * Assign to a variable:
          o update address in pointer-to-pointer for the local
            namespace's record to point to the new object.
          o do reference-count handling
    * Delete a variable:
          o update address in pointer-to-pointer to be NULL (this may
            result in there being no non-NULL entries in the tables (a
            NameError if anything tries to access the name from those
            namespaces))
          o do reference-count handling

Imagined impact:

    * namespace memory overhead is increased (considerably), you wind up
      with caches similar to the local-namespace one for all levels with
      entries for all names in all namespaces at the highest level.
    * external accesses still need hashtable lookup and
      new-name-assignment available, so you can't do away with it. You
      must cache each resolved name in each lexical namespace, so figure
      (numberOfNames*lexical-depth) pointers, plus the hashed-string to
      pointer-to-pointer table.
    * function compilation overhead is increased as you wind up with
      N(names) * M(namespaces) required lookups for _every_ name in the
      namespace.  This should be a (largely) static single-time charge.
    * name lookup should be faster, as a simple array of known length
      (lexical depth) is being searched for the first non-NULL entry.
    * assignment and deletion in namespaces will be slower
          o assignment to previously unknown values needs to extend the
            size of the table for the given namespace and all parent
            namespace's tables where the name doesn't already exist
    * you cannot delete name-entries from a namespace table once created
      (since there may be large numbers of other namespaces which use
      the pointers defined by that namespace).  You could probably
      create a simple scan to get rid of this limitation (or just use
      reference-counting), but I doubt the benefits would be worth the
      cost, save in rare corner cases.
          o (rare-corner-case-description) would be a potential
            bottleneck in cases where exec/eval is used a lot in a
            particular namespace (as it might, for instance, have
            thousands (or millions) of variables created in the exec'd
            namespaces, with NULL entries in the parent namespace not
            getting cleaned up between iterations.)

Anyway, would be interested to know if someone C-knowledgable has done 
this already and 1) integrated it into Python or psyco already, or 2) 
decided it just isn't a feasible approach?
Mike

_______________________________________
  Mike C. Fletcher
  Designer, VR Plumber, Coder
  http://members.rogers.com/mcfletch/







More information about the Python-list mailing list