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