As an example, floating-point arithmetic often has high throughput, but also high latency. For example, you might be able to start two multiplications every cycle, but it might take five cycles until the result of a multiplication is available. The first is called throughput (two per cycle), the second is latency.
If you perform calculations so that one operation is dependent on the previous one, you may become latency bound. Say you calculate (x0 + y0) * (x1 + y1) * (x2 + y2) * ... If you do this in a naive way, then each multiplication can only start 5 cycles after the previous one, so you end up with 0.2 multiplications and 0.2 additions per cycle even though the processor could do much more work per cycle. That's code that is latency bound.
Hyperthreading is very useful for latency bound code, because it's very easy for the processor to handle two latency bound threads at the same speed as one. If your code is limited by throughput, hyper threading doesn't help one bit. Basically, the worse the code, the more help do you get from hyper threading.