Indeed, profiling is a good start. Then, go back to where selects are issued and check a couple of things:
- table scans instead of index reads are a first sign a deadlock will occur there. Add indexes to avoid table scans
- selects in code which starts transactions should be moved to a point before the transaction is started, or the elements participating in the select should be added to the transaction. If you don't do that, a new connection is started, which will hang on locks set by inserts/updates in a transaction which is also currently going on.