From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on dcvr.yhbt.net X-Spam-Level: X-Spam-ASN: AS4713 221.184.0.0/13 X-Spam-Status: No, score=-4.1 required=3.0 tests=AWL,BAYES_00, MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED,SPF_HELO_NONE,SPF_PASS, UNPARSEABLE_RELAY shortcircuit=no autolearn=ham autolearn_force=no version=3.4.2 Received: from neon.ruby-lang.org (neon.ruby-lang.org [221.186.184.75]) by dcvr.yhbt.net (Postfix) with ESMTP id B66E51F8C8 for ; Fri, 17 Sep 2021 06:41:20 +0000 (UTC) Received: from neon.ruby-lang.org (localhost [IPv6:::1]) by neon.ruby-lang.org (Postfix) with ESMTP id 0EAC8120B2A; Fri, 17 Sep 2021 15:39:55 +0900 (JST) Received: from o1678948x4.outbound-mail.sendgrid.net (o1678948x4.outbound-mail.sendgrid.net [167.89.48.4]) by neon.ruby-lang.org (Postfix) with ESMTPS id 89B13120B2B for ; Fri, 17 Sep 2021 15:39:52 +0900 (JST) Received: by filterdrecv-7bc86b958d-ctgkz with SMTP id filterdrecv-7bc86b958d-ctgkz-1-61443886-53 2021-09-17 06:41:10.707852087 +0000 UTC m=+1326051.198859050 Received: from herokuapp.com (unknown) by ismtpd0178p1iad2.sendgrid.net (SG) with ESMTP id nNJWYm4DSJiUnafyNZNHxA for ; Fri, 17 Sep 2021 06:41:10.696 +0000 (UTC) Date: Fri, 17 Sep 2021 06:41:10 +0000 (UTC) From: "mame (Yusuke Endoh)" Message-ID: References: Mime-Version: 1.0 X-Redmine-Project: ruby-master X-Redmine-Issue-Tracker: Feature X-Redmine-Issue-Id: 18176 X-Redmine-Issue-Author: mame X-Redmine-Issue-Assignee: mame X-Redmine-Sender: mame X-Mailer: Redmine X-Redmine-Host: bugs.ruby-lang.org X-Redmine-Site: Ruby Issue Tracking System X-Auto-Response-Suppress: All Auto-Submitted: auto-generated X-Redmine-MailingListIntegration-Message-Ids: 81497 X-SG-EID: =?us-ascii?Q?YbSlef6ZOa=2FS=2FuqSxXRzl42MttQDxKOujGe43WuBjI7JKMg2OkmRsyzG5za6L9?= =?us-ascii?Q?e1flZkYZ9OViVy5Lc4acvpZtygmMa2TztBm+Ca8?= =?us-ascii?Q?OBudnqjzhiGlh6jD8njeh+pC9MJj=2FfDNiDYUzVL?= =?us-ascii?Q?o5nSUzwVTztthO7kL9Hh70xmkCX8gBT7Ky8YE1I?= =?us-ascii?Q?GRC4FNRYv1nqvglPEnVByoUBuzwh1UgT8A3vGis?= =?us-ascii?Q?Y4ix88Dx2GO+Cx1TFebGS0ENciuGdE457ah+jww?= =?us-ascii?Q?RHtDAeMXvBB8urBljcfqw=3D=3D?= To: ruby-core@ruby-lang.org X-Entity-ID: b/2+PoftWZ6GuOu3b0IycA== X-ML-Name: ruby-core X-Mail-Count: 105321 Subject: [ruby-core:105321] [Ruby master Feature#18176] Make Coverage suspendable X-BeenThere: ruby-core@ruby-lang.org X-Mailman-Version: 2.1.15 Precedence: list Reply-To: Ruby developers List-Id: Ruby developers List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Errors-To: ruby-core-bounces@ruby-lang.org Sender: "ruby-core" Issue #18176 has been reported by mame (Yusuke Endoh). ---------------------------------------- Feature #18176: Make Coverage suspendable https://bugs.ruby-lang.org/issues/18176 * Author: mame (Yusuke Endoh) * Status: Open * Priority: Normal * Assignee: mame (Yusuke Endoh) ---------------------------------------- I'd like to add `Coverage.suspend`, `Coverage.resume`, and some methods. ## Synopsis ``` 1: # target.rb 2: def foo 3: :foo 4: end 5: 6: def bar 7: :bar 8: end 9: 10: def baz 11: :baz 12: end ``` ``` require "coverage" # Similar to Coverage.start, but does not start the measurement itself Coverage.setup(oneshot_lines: true) load "target.rb" foo # This call is not counted Coverage.resume # Start the measurement bar # This call is counted Coverage.suspend # Stop the measure baz # This call is not counted # The result is only for Line 7, the body of method "bar" p Coverage.result #=> {"target.rb"=>{:oneshot_lines=>[7]}} ``` ## Background The motivation is to divide modules for large web services. For web services with a long history, we tend to lose track of the dependencies between modules. Using this proposal and oneshot coverage, we can gather information about the code used to process a particular endpoint with almost no runtime cost. Gathering the information for some endpoints will give a hint to isolate the modules. I've received similar requests in the past to make Coverage restartable but I didn't understand the need for it. (Sorry about that!) I heard directly from those who were actually in trouble in our company, and I finally understand. Also, the introduction of oneshot coverage, which can now be measured at almost no cost, has increased the demand for suspendable coverage. ## New APIs * `Coverage.setup`: Almost the same as `Coverage.start` but does not start the measurement itself. * `Coverage.resume`: Start/resume the coverage measurement. * `Coverage.suspend`: Suspend the coverage measurement; it is restartable by using `Coverage.resume`. * `Coverage.state`: Returns the current state: `:idle`, `:suspended`, and `:running`. `Coverage.start(...)` is now the same as `Coverage.start(...); Coverage.resume`. `Coverage.running?` is the same is `Coverage.state == :running`. ## Discussion * Currently, I think `Coverage.suspend` makes sense only for oneshot coverage, but it supports traditional coverage too, for a unknown use case. However, I may disallow it if we find any problems. * It is ideal to measure multiple oneshot coverage for each endpoint together, but it was difficult for me to implement it efficiently. My co-workers say that this feature is still valuable even with the limitation. * Another idea is to use TracePoint. However, I'd like to introduce this feature to the coverage library because (1) the runtime cost of TracePoint seems not to be negligible according to our preliminary experiment, (2) we can use an ecosystem for oneshot coverage (e.g., https://github.com/riseshia/oneshot_coverage), and (3) the changeset for coverage is not so large. ## Implementation https://github.com/ruby/ruby/pull/4856 Any comments are welcome. -- https://bugs.ruby-lang.org/