Friday, October 19, 2007

Observation on a Comcast network

I moved to a new apartment a month ago, and Comcast didn't disconnect the previous resident, so my roommates and I had been using Comcast for free. This is what I found out about their network.

This is pulled from my memory because they disconnected the cable on Monday.
  1. When I upload a file, I could send the first few megabytes at 1MB/s, then it gets throttled down to 30KB/s or less. That means bandwidth throttling does not kick in for the first few seconds of a connection. Afterwards, data is let through in short bursts. I could, however, fire up multiple TCP connections and maintain 30KB/s across all of them. The throttling appears to be connection oriented.
  2. Even low-bandwidth, long lasting TCP connections, such as Skype and SSH, get randomly cut off. There is no "connection reset," and it simply gets stalled. Sometimes that happens every 10 minutes. Sometimes it could stay on for 10 hours. The median is around 2 hours.
It is difficult to throttle bandwidth on a cable network. They can't let the individual cable modems govern itself because users can use their own modem and workaround the bandwidth policy. The next possibility is at the gateway. That's difficult too because all modems in the neighborhood share the same "ether" before reaching the gateway. Doing bandwidth accounting for each IP address is going to be expensive for the gateway router. That's why Comcast bandwidth throttle is connection based.

What I observed is peculiar to how Comcast culls p2p traffic on their network, by making long-hanging TCP connections unreliable. However, it's interesting how Comcast allows the first few outgoing MBs at full speed. Since SMTP connections are short, this allows spammer botnets to go off at full speed.

In other words, Comcast favors spammers over p2p file sharing, Skype, and SSH.

There is a workaround. File sharing protocol should be redesigned to dynamically create and tear down multiple, simultaneous TCP connections. And it should be able to distribute traffic across these TCP connections.

Maybe Comcast will eventually move to discourage short, high-bandwidth TCP connections as well, but that means spammers will be hit, and we end up with less spam. It's a win-win situation for the end user regardless.

Haskell, not your usual programming language

I am learning Haskell, and these are the points I came up with that summarizes the shock with the language. I'm proficient in other strict, unpure functional languages.
  1. Haskell is truly lazy. If there wasn't a need to print anything to the terminal, then computation simply would not happen. In other words, computation is bootstrapped by a side-effect. This explains why the main() expression in Haskell is an IO () monad. Program won't run without being a monad.
  2. An expression with a monadic type simply means it's using call-by-value semantics rather than the usual call-by-need in Haskell. It's analogous to the lazy keyword in O'Caml, which is used for call-by-need evaluation in a call-by-value language. It might be more comfortable for someone like me to start writing in the monad language of Haskell.
  3. There is no signaling mechanism in Haskell, but you can timeout a computation by running it on a separate thread, wait for the result or for the timeout on the current thread, then kill the computation thread if it runs out of time. This is how it is implemented in the System.Timeout module.
  4. Naturally, threads are also monad expressions. Even being a monad, thread won't run if it doesn't cause any side-effects. As a result, System.Timeout only works with expressions of a monadic type. Computation cannot be forced by simply lifting the expression to a monad using the return function.
  5. Haskell concurrency implementation only performs context switching when the program allocates from the heap. As a result, the following expressions do not time out (run forever):
    • length (repeat 1)
    • let xs = 1 : xs in length xs
    But the following do:
    • length [1..]
    • let xs = make_xs () where make_xs () = 1 : make_xs () in length xs
    Note that length xs does not terminate when xs is infinite. For brevity, the result of all the expressions above are printed using IO.putStr, which is the easiest way to force evaluation.