[Cryptech-Commits] [sw/stm32] 02/08: Copy profiling code from MCUOnEclipse.

git at cryptech.is git at cryptech.is
Thu Sep 7 22:42:02 UTC 2017


This is an automated email from the git hooks/post-receive script.

paul at psgd.org pushed a commit to branch profiling
in repository sw/stm32.

commit 9ecd51ab1028e8033057df3117aac27f6f2cd406
Author: Paul Selkirk <paul at psgd.org>
AuthorDate: Thu May 4 15:23:10 2017 -0400

    Copy profiling code from MCUOnEclipse.
---
 libraries/libprof/README.txt |   6 +
 libraries/libprof/gmon.c     | 343 +++++++++++++++++++++++++++++++++++++++++++
 libraries/libprof/gmon.h     | 177 ++++++++++++++++++++++
 libraries/libprof/profil.c   |  94 ++++++++++++
 libraries/libprof/profil.h   |  60 ++++++++
 libraries/libprof/profiler.S |  28 ++++
 6 files changed, 708 insertions(+)

diff --git a/libraries/libprof/README.txt b/libraries/libprof/README.txt
new file mode 100644
index 0000000..2df8b96
--- /dev/null
+++ b/libraries/libprof/README.txt
@@ -0,0 +1,6 @@
+Copied from https://github.com/ErichStyger/mcuoneclipse.git,
+directory Examples/KDS/FRDM-K64F120M/FRDM-K64F_Profiling/Profiling,
+commit 9b7eedddd8b24968128582aedc63be95b61f782c,
+dated Mon Jan 9 16:56:17 2017 +0100.
+(This is in turn adapted from Cygwin, and can be found in newlib distributions.)
+
diff --git a/libraries/libprof/gmon.c b/libraries/libprof/gmon.c
new file mode 100644
index 0000000..2be8bb2
--- /dev/null
+++ b/libraries/libprof/gmon.c
@@ -0,0 +1,343 @@
+/*-
+ * Copyright (c) 1983, 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*
+ * This file is taken from Cygwin distribution. Please keep it in sync.
+ * The differences should be within __MINGW32__ guard.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <unistd.h>
+#include "gmon.h"
+#include "profil.h"
+#include <stdint.h>
+#include <string.h>
+
+#define MINUS_ONE_P (-1)
+#define bzero(ptr,size) memset (ptr, 0, size);
+#define ERR(s) write(2, s, sizeof(s))
+
+struct gmonparam _gmonparam = { GMON_PROF_OFF, NULL, 0, NULL, 0, NULL, 0, 0L, 0, 0, 0};
+static char already_setup = 0; /* flag to indicate if we need to init */
+static int	s_scale;
+/* see profil(2) where this is described (incorrectly) */
+#define		SCALE_1_TO_1	0x10000L
+
+static void moncontrol(int mode);
+
+/* required for gcc ARM Embedded 4.9-2015-q2 */
+#if 0
+void *_sbrk(int incr) {
+  extern char __HeapLimit; /* Defined by the linker */
+  static char *heap_end = 0;
+  char *prev_heap_end;
+
+  if (heap_end==0) {
+    heap_end = &__HeapLimit;
+  }
+  prev_heap_end = heap_end;
+  heap_end += incr;
+  return (void *)prev_heap_end;
+}
+#endif
+
+static void *fake_sbrk(int size) {
+  void *rv = malloc(size);
+  if (rv) {
+    return rv;
+  } else {
+    return (void *) MINUS_ONE_P;
+  }
+}
+
+void monstartup (size_t lowpc, size_t highpc) {
+	register size_t o;
+	char *cp;
+	struct gmonparam *p = &_gmonparam;
+
+	/*
+	 * round lowpc and highpc to multiples of the density we're using
+	 * so the rest of the scaling (here and in gprof) stays in ints.
+	 */
+	p->lowpc = ROUNDDOWN(lowpc, HISTFRACTION * sizeof(HISTCOUNTER));
+	p->highpc = ROUNDUP(highpc, HISTFRACTION * sizeof(HISTCOUNTER));
+	p->textsize = p->highpc - p->lowpc;
+	p->kcountsize = p->textsize / HISTFRACTION;
+	p->fromssize = p->textsize / HASHFRACTION;
+	p->tolimit = p->textsize * ARCDENSITY / 100;
+	if (p->tolimit < MINARCS) {
+		p->tolimit = MINARCS;
+	} else if (p->tolimit > MAXARCS) {
+		p->tolimit = MAXARCS;
+	}
+	p->tossize = p->tolimit * sizeof(struct tostruct);
+
+	cp = fake_sbrk(p->kcountsize + p->fromssize + p->tossize);
+	if (cp == (char *)MINUS_ONE_P) {
+		ERR("monstartup: out of memory\n");
+		return;
+	}
+
+	/* zero out cp as value will be added there */
+	bzero(cp, p->kcountsize + p->fromssize + p->tossize);
+
+	p->tos = (struct tostruct *)cp;
+	cp += p->tossize;
+	p->kcount = (u_short *)cp;
+	cp += p->kcountsize;
+	p->froms = (u_short *)cp;
+
+	p->tos[0].link = 0;
+
+	o = p->highpc - p->lowpc;
+	if (p->kcountsize < o) {
+#ifndef notdef
+		s_scale = ((float)p->kcountsize / o ) * SCALE_1_TO_1;
+#else /* avoid floating point */
+		int quot = o / p->kcountsize;
+
+		if (quot >= 0x10000)
+			s_scale = 1;
+		else if (quot >= 0x100)
+			s_scale = 0x10000 / quot;
+		else if (o >= 0x800000)
+			s_scale = 0x1000000 / (o / (p->kcountsize >> 8));
+		else
+			s_scale = 0x1000000 / ((o << 8) / p->kcountsize);
+#endif
+	} else {
+		s_scale = SCALE_1_TO_1;
+	}
+	moncontrol(1); /* start */
+}
+
+void _mcleanup(void) {
+	static const char gmon_out[] = "gmon.out";
+	int fd;
+	int hz;
+	int fromindex;
+	int endfrom;
+	size_t frompc;
+	int toindex;
+	struct rawarc rawarc;
+	struct gmonparam *p = &_gmonparam;
+	struct gmonhdr gmonhdr, *hdr;
+	const char *proffile;
+#ifdef DEBUG
+	int log, len;
+	char dbuf[200];
+#endif
+
+	if (p->state == GMON_PROF_ERROR) {
+		ERR("_mcleanup: tos overflow\n");
+	}
+	hz = PROF_HZ;
+	moncontrol(0); /* stop */
+	proffile = gmon_out;
+	fd = open(proffile , O_CREAT|O_TRUNC|O_WRONLY|O_BINARY, 0666);
+	if (fd < 0) {
+		perror( proffile );
+		return;
+	}
+#ifdef DEBUG
+	log = open("gmon.log", O_CREAT|O_TRUNC|O_WRONLY, 0664);
+	if (log < 0) {
+		perror("mcount: gmon.log");
+		return;
+	}
+	len = sprintf(dbuf, "[mcleanup1] kcount 0x%x ssiz %d\n",
+	    p->kcount, p->kcountsize);
+	write(log, dbuf, len);
+#endif
+	hdr = (struct gmonhdr *)&gmonhdr;
+	hdr->lpc = p->lowpc;
+	hdr->hpc = p->highpc;
+	hdr->ncnt = p->kcountsize + sizeof(gmonhdr);
+	hdr->version = GMONVERSION;
+	hdr->profrate = hz;
+	write(fd, (char *)hdr, sizeof *hdr);
+	write(fd, p->kcount, p->kcountsize);
+	endfrom = p->fromssize / sizeof(*p->froms);
+	for (fromindex = 0; fromindex < endfrom; fromindex++) {
+		if (p->froms[fromindex] == 0) {
+			continue;
+		}
+		frompc = p->lowpc;
+		frompc += fromindex * HASHFRACTION * sizeof(*p->froms);
+		for (toindex = p->froms[fromindex]; toindex != 0; toindex = p->tos[toindex].link) {
+#ifdef DEBUG
+			len = sprintf(dbuf,
+			"[mcleanup2] frompc 0x%x selfpc 0x%x count %d\n" ,
+				frompc, p->tos[toindex].selfpc,
+				p->tos[toindex].count);
+			write(log, dbuf, len);
+#endif
+			rawarc.raw_frompc = frompc;
+			rawarc.raw_selfpc = p->tos[toindex].selfpc;
+			rawarc.raw_count = p->tos[toindex].count;
+			write(fd, &rawarc, sizeof rawarc);
+		}
+	}
+	close(fd);
+}
+
+/*
+ * Control profiling
+ *	profiling is what mcount checks to see if
+ *	all the data structures are ready.
+ */
+static void moncontrol(int mode) {
+	struct gmonparam *p = &_gmonparam;
+
+	if (mode) {
+		/* start */
+		profil((char *)p->kcount, p->kcountsize, p->lowpc, s_scale);
+		p->state = GMON_PROF_ON;
+	} else {
+		/* stop */
+		profil((char *)0, 0, 0, 0);
+		p->state = GMON_PROF_OFF;
+	}
+}
+
+void _mcount_internal(uint32_t *frompcindex, uint32_t *selfpc) {
+  register struct tostruct	*top;
+  register struct tostruct	*prevtop;
+  register long			toindex;
+  struct gmonparam *p = &_gmonparam;
+
+  if (!already_setup) {
+    extern char __etext; /* end of text/code symbol, defined by linker */
+    already_setup = 1;
+    monstartup(0x410, (uint32_t)&__etext);
+  }
+  /*
+   *	check that we are profiling
+   *	and that we aren't recursively invoked.
+   */
+  if (p->state!=GMON_PROF_ON) {
+    goto out;
+  }
+  p->state++;
+  /*
+   *	check that frompcindex is a reasonable pc value.
+   *	for example:	signal catchers get called from the stack,
+   *			not from text space.  too bad.
+   */
+  frompcindex = (uint32_t*)((long)frompcindex - (long)p->lowpc);
+  if ((unsigned long)frompcindex > p->textsize) {
+      goto done;
+  }
+  frompcindex = (uint32_t*)&p->froms[((long)frompcindex) / (HASHFRACTION * sizeof(*p->froms))];
+  toindex = *((u_short*)frompcindex); /* get froms[] value */
+  if (toindex == 0) {
+    /*
+    *	first time traversing this arc
+    */
+    toindex = ++p->tos[0].link; /* the link of tos[0] points to the last used record in the array */
+    if (toindex >= p->tolimit) { /* more tos[] entries than we can handle! */
+	    goto overflow;
+	  }
+    *((u_short*)frompcindex) = (u_short)toindex; /* store new 'to' value into froms[] */
+    top = &p->tos[toindex];
+    top->selfpc = (size_t)selfpc;
+    top->count = 1;
+    top->link = 0;
+    goto done;
+  }
+  top = &p->tos[toindex];
+  if (top->selfpc == (size_t)selfpc) {
+    /*
+     *	arc at front of chain; usual case.
+     */
+    top->count++;
+    goto done;
+  }
+  /*
+   *	have to go looking down chain for it.
+   *	top points to what we are looking at,
+   *	prevtop points to previous top.
+   *	we know it is not at the head of the chain.
+   */
+  for (; /* goto done */; ) {
+    if (top->link == 0) {
+      /*
+       *	top is end of the chain and none of the chain
+       *	had top->selfpc == selfpc.
+       *	so we allocate a new tostruct
+       *	and link it to the head of the chain.
+       */
+      toindex = ++p->tos[0].link;
+      if (toindex >= p->tolimit) {
+        goto overflow;
+      }
+      top = &p->tos[toindex];
+      top->selfpc = (size_t)selfpc;
+      top->count = 1;
+      top->link = *((u_short*)frompcindex);
+      *(u_short*)frompcindex = (u_short)toindex;
+      goto done;
+    }
+    /*
+     *	otherwise, check the next arc on the chain.
+     */
+    prevtop = top;
+    top = &p->tos[top->link];
+    if (top->selfpc == (size_t)selfpc) {
+      /*
+       *	there it is.
+       *	increment its count
+       *	move it to the head of the chain.
+       */
+      top->count++;
+      toindex = prevtop->link;
+      prevtop->link = top->link;
+      top->link = *((u_short*)frompcindex);
+      *((u_short*)frompcindex) = (u_short)toindex;
+      goto done;
+    }
+  }
+  done:
+    p->state--;
+    /* and fall through */
+  out:
+    return;		/* normal return restores saved registers */
+  overflow:
+    p->state++; /* halt further profiling */
+    #define	TOLIMIT	"mcount: tos overflow\n"
+    write (2, TOLIMIT, sizeof(TOLIMIT));
+  goto out;
+}
+
+void _monInit(void) {
+  _gmonparam.state = GMON_PROF_OFF;
+  already_setup = 0;
+}
diff --git a/libraries/libprof/gmon.h b/libraries/libprof/gmon.h
new file mode 100644
index 0000000..5eb5180
--- /dev/null
+++ b/libraries/libprof/gmon.h
@@ -0,0 +1,177 @@
+/*	$OpenBSD: gmon.h,v 1.3 1996/04/21 22:31:46 deraadt Exp $	*/
+/*	$NetBSD: gmon.h,v 1.5 1996/04/09 20:55:30 cgd Exp $	*/
+
+/*-
+ * Copyright (c) 1982, 1986, 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *	@(#)gmon.h	8.2 (Berkeley) 1/4/94
+ */
+
+/*
+ * This file is taken from Cygwin distribution. Please keep it in sync.
+ * The differences should be within __MINGW32__ guard.
+ */
+
+#ifndef _SYS_GMON_H_
+#define _SYS_GMON_H_
+
+#ifndef __P
+#define __P(x) x
+#endif
+
+/* On POSIX systems, profile.h is a KRB5 header.  To avoid collisions, just
+   pull in profile.h's content here.  The profile.h header won't be provided
+   by Mingw-w64 anymore at one point. */
+#if 0
+#include <profile.h>
+#else
+#ifndef _WIN64
+#define _MCOUNT_CALL __attribute__ ((regparm (2)))
+extern void _mcount(void);
+#else
+#define _MCOUNT_CALL
+extern void mcount(void);
+#endif
+#define _MCOUNT_DECL __attribute__((gnu_inline)) __inline__ \
+   void _MCOUNT_CALL _mcount_private
+#define MCOUNT
+#endif
+
+/*
+ * Structure prepended to gmon.out profiling data file.
+ */
+struct gmonhdr {
+	size_t	lpc;		/* base pc address of sample buffer */
+	size_t	hpc;		/* max pc address of sampled buffer */
+	int	ncnt;		    /* size of sample buffer (plus this header) */
+	int	version;	  /* version number */
+	int	profrate;	  /* profiling clock rate */
+	int	spare[3];	  /* reserved */
+};
+#define GMONVERSION	0x00051879
+
+/*
+ * histogram counters are unsigned shorts (according to the kernel).
+ */
+#define	HISTCOUNTER	unsigned short
+
+/*
+ * fraction of text space to allocate for histogram counters here, 1/2
+ */
+#define	HISTFRACTION	2
+
+/*
+ * Fraction of text space to allocate for from hash buckets.
+ * The value of HASHFRACTION is based on the minimum number of bytes
+ * of separation between two subroutine call points in the object code.
+ * Given MIN_SUBR_SEPARATION bytes of separation the value of
+ * HASHFRACTION is calculated as:
+ *
+ *	HASHFRACTION = MIN_SUBR_SEPARATION / (2 * sizeof(short) - 1);
+ *
+ * For example, on the VAX, the shortest two call sequence is:
+ *
+ *	calls	$0,(r0)
+ *	calls	$0,(r0)
+ *
+ * which is separated by only three bytes, thus HASHFRACTION is
+ * calculated as:
+ *
+ *	HASHFRACTION = 3 / (2 * 2 - 1) = 1
+ *
+ * Note that the division above rounds down, thus if MIN_SUBR_FRACTION
+ * is less than three, this algorithm will not work!
+ *
+ * In practice, however, call instructions are rarely at a minimal
+ * distance.  Hence, we will define HASHFRACTION to be 2 across all
+ * architectures.  This saves a reasonable amount of space for
+ * profiling data structures without (in practice) sacrificing
+ * any granularity.
+ */
+#define	HASHFRACTION	2
+
+/*
+ * percent of text space to allocate for tostructs with a minimum.
+ */
+#define ARCDENSITY	2 /* this is in percentage, relative to text size! */
+#define MINARCS		 50
+#define MAXARCS		 ((1 << (8 * sizeof(HISTCOUNTER))) - 2)
+
+struct tostruct {
+	size_t	selfpc; /* callee address/program counter. The caller address is in froms[] array which points to tos[] array */
+	long	count;    /* how many times it has been called */
+	u_short	link;   /* link to next entry in hash table. For tos[0] this points to the last used entry */
+	u_short pad;    /* additional padding bytes, to have entries 4byte aligned */
+};
+
+/*
+ * a raw arc, with pointers to the calling site and
+ * the called site and a count.
+ */
+struct rawarc {
+	size_t	raw_frompc;
+	size_t	raw_selfpc;
+	long	raw_count;
+};
+
+/*
+ * general rounding functions.
+ */
+#define ROUNDDOWN(x,y)	(((x)/(y))*(y))
+#define ROUNDUP(x,y)	  ((((x)+(y)-1)/(y))*(y))
+
+/*
+ * The profiling data structures are housed in this structure.
+ */
+struct gmonparam {
+	int		state;
+	u_short		*kcount;    /* histogram PC sample array */
+	size_t		kcountsize; /* size of kcount[] array in bytes */
+	u_short		*froms;     /* array of hashed 'from' addresses. The 16bit value is an index into the tos[] array */
+	size_t		fromssize;  /* size of froms[] array in bytes */
+	struct tostruct	*tos; /* to struct, contains histogram counter */
+	size_t		tossize;    /* size of tos[] array in bytes */
+	long		  tolimit;
+	size_t		lowpc;      /* low program counter of area */
+	size_t		highpc;     /* high program counter */
+	size_t		textsize;   /* code size */
+};
+extern struct gmonparam _gmonparam;
+
+/*
+ * Possible states of profiling.
+ */
+#define	GMON_PROF_ON	  0
+#define	GMON_PROF_BUSY	1
+#define	GMON_PROF_ERROR	2
+#define	GMON_PROF_OFF	  3
+
+void _mcleanup(void); /* routine to be called to write gmon.out file */
+void _monInit(void); /* initialization routine */
+
+#endif /* !_SYS_GMONH_ */
diff --git a/libraries/libprof/profil.c b/libraries/libprof/profil.c
new file mode 100644
index 0000000..24ede21
--- /dev/null
+++ b/libraries/libprof/profil.c
@@ -0,0 +1,94 @@
+/* profil.c -- win32 profil.c equivalent
+
+   Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+   This file is part of Cygwin.
+
+   This software is a copyrighted work licensed under the terms of the
+   Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+   details. */
+
+/*
+ * This file is taken from Cygwin distribution, adopted to be used for bare embeeded targets.
+ */
+#include <stdio.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <math.h>
+#include "profil.h"
+#include <string.h>
+#include <stdint.h>
+
+/* global profinfo for profil() call */
+static struct profinfo prof = {
+  PROFILE_NOT_INIT, 0, 0, 0, 0
+};
+
+/* sample the current program counter */
+void SysTick_Handler(void) {
+  void OSA_SysTick_Handler(void);
+  static size_t pc, idx;
+
+  OSA_SysTick_Handler(); /* call normal Kinetis SDK SysTick handler */
+  if (prof.state==PROFILE_ON) {
+    pc = ((uint32_t*)(__builtin_frame_address(0)))[14]; /* get SP and use it to get the return address from stack */
+    if (pc >= prof.lowpc && pc < prof.highpc) {
+      idx = PROFIDX (pc, prof.lowpc, prof.scale);
+      prof.counter[idx]++;
+    }
+  }
+}
+
+/* Stop profiling to the profiling buffer pointed to by p. */
+static int profile_off (struct profinfo *p) {
+  p->state = PROFILE_OFF;
+  return 0;
+}
+
+/* Create a timer thread and pass it a pointer P to the profiling buffer. */
+static int profile_on (struct profinfo *p) {
+  p->state = PROFILE_ON;
+  return 0; /* ok */
+}
+
+/*
+ * start or stop profiling
+ *
+ * profiling goes into the SAMPLES buffer of size SIZE (which is treated
+ * as an array of u_shorts of size size/2)
+ *
+ * each bin represents a range of pc addresses from OFFSET.  The number
+ * of pc addresses in a bin depends on SCALE.  (A scale of 65536 maps
+ * each bin to two addresses, A scale of 32768 maps each bin to 4 addresses,
+ * a scale of 1 maps each bin to 128k address).  Scale may be 1 - 65536,
+ * or zero to turn off profiling
+ */
+int profile_ctl (struct profinfo *p, char *samples, size_t size, size_t offset, u_int scale) {
+  size_t maxbin;
+
+  if (scale > 65536) {
+    errno = EINVAL;
+    return -1;
+  }
+  profile_off(p);
+  if (scale) {
+    memset(samples, 0, size);
+    memset(p, 0, sizeof *p);
+    maxbin = size >> 1;
+    prof.counter = (u_short*)samples;
+    prof.lowpc = offset;
+    prof.highpc = PROFADDR(maxbin, offset, scale);
+    prof.scale = scale;
+    return profile_on(p);
+  }
+  return 0;
+}
+
+/* Equivalent to unix profil()
+   Every SLEEPTIME interval, the user's program counter (PC) is examined:
+   offset is subtracted and the result is multiplied by scale.
+   The word pointed to by this address is incremented. */
+int profil (char *samples, size_t size, size_t offset, u_int scale) {
+  return profile_ctl (&prof, samples, size, offset, scale);
+}
+
diff --git a/libraries/libprof/profil.h b/libraries/libprof/profil.h
new file mode 100644
index 0000000..af7a3ed
--- /dev/null
+++ b/libraries/libprof/profil.h
@@ -0,0 +1,60 @@
+/* profil.h: gprof profiling header file
+
+   Copyright 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+/*
+ * This file is taken from Cygwin distribution. Please keep it in sync.
+ * The differences should be within __MINGW32__ guard.
+ */
+
+#ifndef __PROFIL_H__
+#define __PROFIL_H__
+
+/* profiling frequency.  (No larger than 1000) */
+#define PROF_HZ			1000
+
+/* convert an addr to an index */
+#define PROFIDX(pc, base, scale)	\
+  ({									\
+    size_t i = (pc - base) / 2;				\
+    if (sizeof (unsigned long long int) > sizeof (size_t))		\
+      i = (unsigned long long int) i * scale / 65536;			\
+    else								\
+      i = i / 65536 * scale + i % 65536 * scale / 65536;		\
+    i;									\
+  })
+
+/* convert an index into an address */
+#define PROFADDR(idx, base, scale)		\
+  ((base)					\
+   + ((((unsigned long long)(idx) << 16)	\
+       / (unsigned long long)(scale)) << 1))
+
+/* convert a bin size into a scale */
+#define PROFSCALE(range, bins)		(((bins) << 16) / ((range) >> 1))
+
+typedef void *_WINHANDLE;
+
+typedef enum {
+  PROFILE_NOT_INIT = 0,
+  PROFILE_ON,
+  PROFILE_OFF
+} PROFILE_State;
+
+struct profinfo {
+  PROFILE_State state; /* profiling state */
+  u_short *counter;			/* profiling counters */
+  size_t lowpc, highpc;		/* range to be profiled */
+  u_int scale;			/* scale value of bins */
+};
+
+int profile_ctl(struct profinfo *, char *, size_t, size_t, u_int);
+int profil(char *, size_t, size_t, u_int);
+
+#endif /* __PROFIL_H__ */
diff --git a/libraries/libprof/profiler.S b/libraries/libprof/profiler.S
new file mode 100644
index 0000000..1aa5c97
--- /dev/null
+++ b/libraries/libprof/profiler.S
@@ -0,0 +1,28 @@
+/*
+ * profiler.S
+ *  Implements the gprof profiler arc counting function.
+ *  Created on: 06.08.2015
+ *      Author: Erich Styger
+ */
+
+    .syntax unified
+    .arch armv7-m
+
+.globl __gnu_mcount_nc
+.type __gnu_mcount_nc, %function
+
+__gnu_mcount_nc:
+#if 0 /* dummy version, doing nothing */
+  mov    ip, lr
+  pop    { lr }
+  bx     ip
+#else
+  push {r0, r1, r2, r3, lr}     /* save registers */
+  bic r1, lr, #1                /* R1 contains callee address, with thumb bit cleared */
+  ldr r0, [sp, #20]             /* R0 contains caller address */
+  bic r0, r0, #1                /* clear thumb bit */
+  bl _mcount_internal           /* jump to internal _mcount() implementation */
+  pop {r0, r1, r2, r3, ip, lr}  /* restore saved registers */
+  bx ip                         /* return to caller */
+#endif
+



More information about the Commits mailing list