  	c.sendq.enqueue(mysg)
  	goparkunlock(&c.lock, "chan send", traceEvGoBlockSend, 3)
  
-@@ -370,7 +390,6 @@ func chanrecv2(t *chantype, c *hchan, elem unsafe.Pointer) (received bool) {
+@@ -257,6 +278,9 @@ func send(c *hchan, sg *sudog, ep unsafe.Pointer, unlockf func()) {
+ 			c.sendx = c.recvx // c.sendx = (c.sendx+1) % c.dataqsiz
+ 		}
+ 	}
++	evID = atomic.Xadd64(&evID, 1)
++	sg.eventid = atomic.Load64(&evID)
++	traceGoSend(evID, c.id, elem2int(ep))
+ 	unlockf()
+ 	if sg.elem != nil {
+ 		sendDirect(c.elemtype, sg, ep)
+@@ -370,7 +394,6 @@ func chanrecv2(t *chantype, c *hchan, elem unsafe.Pointer) (received bool) {
  func chanrecv(t *chantype, c *hchan, ep unsafe.Pointer, block bool) (selected, received bool) {
  	// raceenabled: don't need to check ep, as it is always on the stack
  	// or is new memory allocated by reflect.

 	// someone woke us up
 	if mysg != gp.waiting {
 		throw("G waiting list is corrupted")
@@ -687,3 +709,10 @@ func racesync(c *hchan, sg *sudog) {
 	racereleaseg(sg.g, chanbuf(c, 0))
 	raceacquire(chanbuf(c, 0))
 }

 
 	if debugChan {
 		print("makechan: chan=", c, "; elemsize=", elem.size, "; elemalg=", elem.alg, "; dataqsiz=", size, "\n")
@@ -168,6 +177,8 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 	}
 
 	if sg := c.recvq.dequeue(); sg != nil {
+		sg.cid = c.id
+
 		// Found a waiting receiver. We pass the value we want to send
 		// directly to the receiver, bypassing the channel buffer (if any).
 		send(c, sg, ep, func() { unlock(&c.lock) })
@@ -181,6 +192,10 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 			raceacquire(qp)
 			racerelease(qp)
 		}
+
+		evID = atomic.Xadd64(&evID, 1)
+		traceGoSend(evID, c.id, elem2int(ep))
+
 		typedmemmove(c.elemtype, qp, ep)
 		c.sendx++
 		if c.sendx == c.dataqsiz {
@@ -209,6 +224,12 @@ func chansend(t *chantype, c *hchan, ep unsafe.Pointer, block bool, callerpc uin
 	mysg.selectdone = nil
 	gp.waiting = mysg
 	gp.param = nil
