On Tue, Sep 19, 2000 at 11:27:47AM -0700, [EMAIL PROTECTED] wrote:
> On 19 Sep, Sean Ward wrote:
> 
> > Yep, freeamp as a whole is a lot more bloated than say, winamp or XMMS. The
> > primary size difference comes from the musicbrowser, because it loads all
> > the metadata entries at startup, so has a memory footprint proportional to
> > the number of tracks in your collection. Additionally, there are a bit too
> > many internal copies which go on, which are part of the general musicbrowser
> > issue ;).

Loading cached metadata from a gdbm file.  Nice.  Speedy.
Assert: It looks like it is stored as a series of records with a url key.

> 
> I did some basic snooping around in the codebase to see why we use so
> much memory and what we can do about it. First, the musicbrowser and the
> musiccatalog duplicate the playlist items, which is a known bug and
> would take a serious amount of work to take care of.

So do not tackle that first.

> 
> Second is the our abundant use of string objects, especially in the
> Metadata class. There are 7 string objects (m_artist, m_album, m _title,
> m_genre, m_comment, m_extension, m_guid) which may or may not be all
> filled out.

I have been probing at that.  It could be changed in one session of editing.

> So, I would propose the following as a footprint reducing measure that
> we could easily implement before we release 2.1 and somewhat ease
> crunch.
> 
> 1) Find some code on the net that manages a freestore for small strings

Easier said than done.  Of couse something like hash_map<char*,
unsigned int> makes for a freestore, with the int being a reference
count.  Hash/compare only on the string's value to merge duplicate
string values.  Or to save the int for each string:

API:

Have a hash_set<char*> which holds new refcount 1 strings (and thus
has no int overhead), and a hash_map<char*, unsigned int> which holds
any refcount string.  A duplicate has to be searched for in both the
hash_map and hash_set when adding a new string.  When ++refcount on
char* in the hash_set, move char* to the hash_map with refcount 2.
Note: If the stored refcount in hash_map is zero, it means the string
is static and need never be freed, and the refcount stays at zero.
When --refcount, do not move char* back from hash_map to hash_set,
just leave it in hash_set with a refcount of 1.

Side note: If you want to read out the strings in sorted order, make
them in a set and map instead of hash_set and hash_map.  Then by
traversing both lists in parallel one can easily get the char* in
sorted order, including duplicates.

All char* that are returned act as keys, and point to stored strings.
Passing in null is simply ignored.  Returning null would indicate
probably fatal error. The return char * keys could be wrapped in
classes that "know" their type and can handle unref. (see end)

char * freestore::insert_static(const char * s)

put s with refcount zero into the freestore, and return s.  If duplicate
exists, set its refcount to zero and return it instead.

char * freestore::insert_dynamic(char * s)

take ownership of and store s.  If duplicate exists and if refcount>0
then ++refcount and free s and return the existing pointer.  If no
duplicate, store s with refcount 1 and return s.

char * freestore::insert_duplicate(const char * s)

If duplicate of s exists, ++refcount and return the existing stored
pointer.  If no duplicate, insert a copy of s with refcount 1 and return
the address of the copy.

void freestore::ref(const char * s)

s must be in freestore, just ++refcount if refcount>0.

void freestore::unref(char * s)

s must be in freestore, if refcount >0 then --refcount and if now
zero, free it.

> 2) Add an instance of the freestore to the context object so its
>  available all over the place.

Of course.

> 3) Instead of using strings in the Metadata class, we use pointers to
>  entries in the freestore. We convert to and from strings when the
>  accessor methods are called.

Exactly.  Also, merge duplicates.  In particular, separating pathname
from filename would allow all the songs in a directory to share the
same path string.  But that means screwing up the url naming scheme,
which makes this a separate optimization to be worried about later.

> 
> The only outside code change that needs to happen is that when someone
> creates a metadata/playlist object, the freestore pointer needs to get
> passed in.

Hmmm....here you seem to want the context (which is currently
singular?) to not be a guaranteed singleton.  But the freestore could
be a singleton, why not?  Then you could access it without needing to
pass its address to MetaData/PlaylistItem every single time.

---

A wierd hack, but space efficient.  Note that the size of each
album_key instance is only the size of one char*.  Besides, no
hairbrained amateur scheme in C++ is complete without a YASPC (yet
another smart pointer class).

extern freestore& get_album_freestore();  // Global function or method of singleton.

// No virtual methods!
class album_key {
private:
        char * album;
        album_key& operator=(const album_key& other) {};
public:
        album_key() : album(NULL) {};
        album_key(char* s) : album(s) {
                // Assume s has been stored with refcount 1 already
        };
        album_key(const album_key& other) album(other.album) {
                get_album_freestore().ref(album);
        };
        ~album_key() {
                get_album_freestore().unref(album);
        };
        const char * name() {
                return album;
        };
        const string as_string() {
                return album;
        };
};
_______________________________________________
[EMAIL PROTECTED]
http://www.freeamp.org/mailman/listinfo/freeamp-dev

Reply via email to