swiftlang / swiftlang/swift-corelibs-libdispatch

Implementing an alternative to Block_copy

Open
#795 0 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C
Stars
2.6k
Forks
496
Avg merge
2d 6h
Merged PRs (30d)
3

Description

First off, what I'm doing is definitely a Bad Idea (TM), but let's leave that aside for the moment! 😄

I've been having fun combining blocks and structs to create "objects". It works just fine... except for performance.

From https://github.com/williamcotton/express-c/tree/master/research/blocks

/* Baseline */
int main() {
  printf("string baseline!\n");
  for (int i = 0; i < LOOPS; i++) {
    char *test = "test";
    size_t len = strlen(test);
    char *new_str = malloc(len + 1);
    for (size_t i = 0; i < len; i++) {
      new_str[len - i - 1] = test[i];
    }
    new_str[len] = '\0';
    free(new_str);
  }
}
/* Bad Idea (TM) "objects" */
int main() {
  printf("string block!\n");
  for (int i = 0; i < LOOPS; i++) {
    string_t *test = string("test");
    test->reverse();
    test->free();
  }
}

The latter, which uses the string "object" below, is about 25 times slower than the former, which is to be expected considering all of the extra memory allocations.

Is there a way to reduce the number of memory allocations by implementing a version of Block_copy designed for the circus act you see below? That is, could the scope that each block closes over be copied just once instead of for each "method"?

From https://github.com/williamcotton/express-c/blob/master/src/string/string.c#L202

string_t *string(const char *strng) {
  string_t *s = malloc(sizeof(string_t));
  s->value = strdup(strng);
  s->size = strlen(s->value);

  s->blockCopyCount = 0;
  s->blockCopy = Block_copy(^(void *block) {
    void *ptr = Block_copy(block);
    s->blockCopies[s->blockCopyCount++] = (malloc_t){.ptr = ptr};
    return ptr;
  });

  s->print = s->blockCopy(^(void) {
    printf("%s\n", s->value);
  });

  s->concat = s->blockCopy(^(const char *str) {
    size_t size = s->size + strlen(str);
    char *new_str = malloc(size + 1);
    strlcpy(new_str, s->value, size + 1);
    strlcat(new_str, str, size + 1);
    free(s->value);
    s->value = new_str;
    s->size = size;
    return s;
  });

  ...

}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the referenced research/blocks examples and src/string/string.c around line 202 to understand the allocation pattern and Block_copy usage. Determine whether the requested shared-closure behavior fits this project and what API or implementation scope would be required; done would be a documented, agreed-upon design or a clearly scoped change.

Written by the indexing model from the issue text.

Assessment

Tech stack
c
Domain
operating-systems
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
20/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.