Wouldn’t it be cool if everyone had a GPS device in their car, used it during rush hours and the device would connect to a central server, maybe through AT&T (!!!) and load balance the streets?
For example, it could find the best route based on traffic load on different routes to a destination.
September 2008
Idea: A load balancer for the streets
Finding and fixing bottlenecks-slow parts in your PHP code
Sometimes you can see that your script is running slow but if you don’t have a lot of experience you don’t know how to find out what’s the problem and where to start looking for it.
You then naturally start looking at your loops and things like that, but from my experience the bottleneck is almost always somewhere you are not expecting.
It’s often in your database queries or calling external resources. The ones that look so innocent
To find out where the issue is, you can use these two functions:
function benchmark() { static $start = NULL; if( is_null($start) ) { $start = get_microtime(); } else { $benchmark = get_microtime() - $start; $start = get_microtime(); return $benchmark; } } function get_microtime() { list($usec, $sec) = explode(" ", microtime()); return ((float)$usec + (float)$sec); }
Place these 2 functions on top of your code and place these in your code:
benchmark(); /* The first call will initialize the function */ /* Some code */ echo benchmark() .'<br />'; /* Some more code */ echo benchmark() .'<br />'; /* Yet more code */ echo benchmark() .'<br />';
This will show you numbers like 0.02341… etc.
People usually don’t say how long part of a script should run or how long is too long but I’ll tell you that if you get numbers like 0.1, 0.2, 0.4 or 1.4 then you have a problem and your application might not scale well.
If this is the case then you should use PHPCache and cache the results of those slow parts, even for 1 minute at a time, this will bring those numbers down to 0.02 or 0.01…
The other thing you should do first is to check out your queries, use PHPMyAdmin, try “EXPLAIN your query” and see if MySQL is using your indexes properly. (If you indexed your tables well to begin with)
Query optimization is a big topic, I will write about that more later but sometimes query optimization won’t help you because your query is too nasty and you can’t do it any other way. (With your level of experience)
I hope this helps someone
PHPCache; a new version of PHPCache is available
A new version of PHPCache is available.
This one has 5 new methods:
PHPCache::set_expire($key)
Which will set the expiration of the cache record for $key in the past, I think this method has some advantages over deleting the key all together.
PHPCache::remove($key)
Will completely remove the row.
PHPCache::clean_up()
This method will be called when ever you construct/configure a new PHPCache object with PHPCache::configure($database) method and does two things:
1 – Will delete all the old keys on the table, you can control how often this happens with 2 constants:
PHPCACHE_GC_PROBABILITY & PHPCACHE_GC_DIVISOR
If you set PHPCACHE_GC_PROBABILITY to 10 and PHPCACHE_GC_DIVISOR to 100, then when ever you configure the PHPCache object with PHPCache::configure($database); there will be 10% chance that the garbage collector will delete the old rows.
The default value is 1%.
2 – It will optimize the table PHPCache is using, you can also control how often this happens through 2 other constants:
PHPCACHE_TO_PROBABILITY & PHPCACHE_TO_DIVISOR
It works similar to #1 and default value is 10%.
PHPCache::gc()
Will delete the old rows anytime you call this method, it doesn’t care about PHPCACHE_GC_PROBABILITY & PHPCACHE_GC_DIVISOR
One place to use this would be a cron tab.
PHPCache::optimize_table()
Will optimize PHPCache’s table and doesn’t care about
PHPCACHE_TO_PROBABILITY & PHPCACHE_TO_DIVISOR
This new version has some more minor improvements over the old one too.
A cool break_words function for PHP
I wrote this a while back, if you wrote a better one please let me know
function break_words($text, $length, $result_length, $append) { preg_match_all('#([^ ]{' .$length .',})#', $text, $matches); foreach($matches[1] as $word) { $word = trim($word); $text = str_replace($word, substr($word, 0, $result_length) .$append, $text); } return $text; }
This function will break the long words in string $text, which are more than $length to be maximum $result_length characters and appends what ever you pass in as $append.
Example usage:
$post = break_words($post, 30, 30, '');
I’m not convinced that this is the best solution.
A binary tree node insertion function
I was working on this for a few days and came up with 3 versions of this function, don’t even ask for the first one.
Here is the second version which is inspired by K&R’s example:
(Just read BTree as Binary Tree)
/** First Version **/ void BTree_Store(BTree *t, char *key, void *elem) { t->root = BTree_Install(t, t->root, key, elem); } Node *BTree_Install(BTree *t, Node *parent, char *key, void *elem) { int cmpResult; if (parent == NULL) parent = BTree_NewNode(t, key, elem); else { cmpResult = t->cmpfn(parent->key, key, BTREE_MAX_KEY_SIZE); if (cmpResult == 0) memcpy(parent->elem, elem, t->elemSize); else if (cmpResult < 0) parent->lnode = BTree_Install(t, parent->lnode, key, elem); else parent->rnode = BTree_Install(t, parent->rnode, key, elem); } return parent; }
The problem with this (or my problem
) is that I don’t like creation of stack frames and local variables over and over here, it might need like 40 of them and I knew I could do better so I came up with this version:
/** Second Version **/ void BTree_Store(BTree *t, char *key, void *elem) { Node **n; int cmpResult; n = &t->root; while (*n != NULL) { cmpResult = t->cmpfn((*n)->key, key, BTREE_MAX_KEY_SIZE); if (cmpResult == 0) break; else if (cmpResult < 0) n = &((*n)->lnode); else n = &((*n)->rnode); } if (cmpResult == 0) memcpy((*n)->elem, elem, t->elemSize); else *n = BTree_NewNode(t, key, elem); }
I actually love this version, it’s quick, compact and right to the point.
Here is how the node and the tree structures look like:
struct node { char *key; /* Owned by tree */ void *elem; /* Owned by tree */ struct node *lnode; struct node *rnode; }; typedef struct node Node; struct btree { Node *root; int elemSize; int numNodes; int memUsed; int (*cmpfn)(const char *, const char *, size_t); }; typedef struct btree BTree;
The cmpfn is strncmp by defaults because keys are char *, here are the tree & node construction and destruction functions:
void BTree_Init(BTree *t, int elemSize, int (*cmpfn)(const char *, const char *, size_t)) { t->elemSize = elemSize; t->cmpfn = cmpfn != NULL ? cmpfn : BTREE_DFLT_CMP_FN; t->numNodes = 0; t->memUsed = 0; t->root = NULL; } void BTree_Dispose(BTree *t) { BTree_DisposeNodeRecursive(t, t->root); } static Node *BTree_NewNode(BTree *t, char *key, void *elem) { Node *n; n = (Node *) malloc(sizeof(Node)); n->elem = malloc(t->elemSize); memcpy(n->elem, elem, t->elemSize); n->key = (char *) malloc(strlen(key) + 1); /* +1 for '\0' */ strcpy(n->key, key); n->lnode = NULL; n->rnode = NULL; t->memUsed += BTREE_NODE_SIZE(t, key); t->numNodes++; return n; } static void BTree_DisposeNode(BTree * t, Node *n) { t->memUsed -= BTREE_NODE_SIZE(t, n->key); t->numNodes--; free(n->key); free(n->elem); free(n); } static void BTree_DisposeNodeRecursive(BTree *t, Node *n) { if (n->lnode != NULL) BTree_DisposeNodeRecursive(t, n->lnode); if (n->rnode != NULL) BTree_DisposeNodeRecursive(t, n->rnode); BTree_DisposeNode(t, n); }
Here is the BTREE_NODE_SIZE macro:
#define BTREE_NODE_SIZE(t, k) sizeof(Node) + strlen(k) + 1 + t->elemSizeAnd here is the search function:
Node *BTree_FindNode(BTree *t, char *key) { Node *n; int cmpResult; n = t->root; while (n != NULL) { cmpResult = t->cmpfn(n->key, key, BTREE_MAX_KEY_SIZE); if (cmpResult == 0) return n; else if (cmpResult < 0 && n->lnode != NULL) n = n->lnode; else if (n->rnode != NULL) n = n->rnode; else break; } return BTREE_KEY_NOT_FOUND; } void *BTree_Get(BTree *t, char *key) { Node *n; n = BTree_FindNode(t, key); return n != BTREE_KEY_NOT_FOUND ? n->elem : BTREE_KEY_NOT_FOUND; }
The only problem with this tree is that if you store sorted data you will end up with a linked list rather than a binary search tree so I’m working on a self balancing binary search tree which is very chalanging but I love chalanges
So we launched Bloggapedia’s new features
Finally today we launched Bloggapedia’s new features and we are very happy with it.
We are not done yet and more features are on their way.
Here is my profile:
http://www.bloggapedia.com/user.php?u=14679

I'm a programmer at 